Bölüm 4: Kalıtım
Giriş
Öğrenme Çıktıları
Kalıtımı (inheritance), üst sınıf ve alt sınıf kavramlarını tanımlamak; “is-a” ilişkisini tanımak.
extends ile alt sınıf yazmak; neyin miras alındığını, neyin alınmadığını açıklamak.
super(...) ve super.metot() kullanmak; yapıcı zincirinin çalışma sırasını izlemek.
Metodu geçersiz kılmak (overriding), aşırı yüklemeden (overloading) ayırmak, @Override kullanmak.
protected erişimini ve final ile kalıtımın nasıl sınırlandığını açıklamak.
toString, equals ve hashCode metotlarını doğru yazmak; == ile equals farkını bilmek.
Kalıtım Kavramı
Kalıtım Nedir?
- Kalıtım (Inheritance): mevcut bir sınıfın nitelik ve metotlarını miras alıp yeni veya değiştirilmiş yeteneklerle zenginleştirerek yeni bir sınıf oluşturmaktır.
- Mevcut sınıf: üst sınıf (superclass, temel sınıf).
- Yeni sınıf: alt sınıf (subclass, türetilmiş sınıf).
- Alt sınıfa yeni nitelik ve metotlar eklenebilir; miras alınan nitelikler yeniden tanımlanmaz.
en, boy ve alan() bilgisini ekler.Kalıtım Kavramı
extends ile Alt Sınıf
// Temel sınıf (üst sınıf) public class Sekil { // Temel sınıfa ait nitelik ve metotlar // ... } // Yeni sınıf (alt sınıf), Sekil'den türer public class Dikdortgen extends Sekil { // Yeni sınıfa ait nitelik ve metotlar // ... }
- Söz dizimi:
class AltSinif extends UstSinif.extends: “genişletir”. extendssonrasına yalnızca bir sınıf yazılabilir.- Alt sınıf, üst sınıfın
publicveprotectedüyelerini kendi üyesiymiş gibi kullanır. - Üst sınıftaki aynı adlı niteliği alt sınıfta yeniden tanımlamak onu gizler (hiding); iki ayrı değişken oluşur ve kafa karıştırır. Yapılmamalıdır.
extendsyazılmazsa sınıf, gizliceObjectsınıfından türer.
Kalıtım Kavramı
Alt ve Üst Sınıf
- Alt sınıf, üst sınıfın davranışlarını sergiler; ek olarak kendine özgü davranışlar da sergiler.
- Kalıtım bu yüzden özelleştirme (specialization) olarak da adlandırılır: alt sınıf daha özel bir grubu temsil eder.
- Her kedi bir hayvandır, ama her hayvan kedi değildir.
- Java sınıf hiyerarşisi,
java.langpaketindekiObjectsınıfı ile başlar. - Her sınıf, doğrudan veya dolaylı olarak
Objectsınıfından miras alır.
Kalıtım Kavramı
Neler Miras Alınır?
| Üye | Alt sınıfa geçer mi? | Not |
|---|---|---|
public / protected nitelik ve metotlar | Evet | Alt sınıfta doğrudan kullanılır. |
| Belirteçsiz (paket erişimli) üyeler | Yalnızca aynı paketteyse | Başka paketteki alt sınıf erişemez. |
private nitelikler | Nesnede yer alır, ama doğrudan erişilemez | Üst sınıfın public/protected metotlarıyla (getter, setter) kullanılır. |
private metotlar | Hayır | Görünmez; geçersiz kılınamaz. |
| Yapıcılar (constructors) | Hayır | Miras alınmaz; alt sınıf yapıcısı super(...) ile çağırır. |
static üyeler | Erişilebilir | Sınıfa aittir; geçersiz kılınmaz, yalnızca gizlenebilir. |
Kısaca: alt sınıf nesnesinin içinde üst sınıfın bütün nitelikleri vardır; hangisine doğrudan erişilebileceğini erişim belirteci belirler.
Hayvan Örneği
Hayvan Sınıf Hiyerarşisi
Ortak nitelik ve metotlar bir kez, Hayvan sınıfında yazılır. Her alt sınıf konus() metodunu kendine göre geçersiz kılar ve kendine özgü bir metot ekler. UML'de kalıtım, ucu üst sınıfa dönük içi boş üçgen okla gösterilir.
Hayvan Örneği
Hayvan ve Kopek Sınıfları
public class Hayvan { private String isim; // ortak nitelikler private int yas; private double saglik; public Hayvan(String isim, int yas) { this.isim = isim; this.yas = yas; this.saglik = 100.0; } public String getIsim() { return isim; } // private isim'e erişim yolu public void konus() { System.out.println("Bu hayvan konuşur."); } public void uyu() { saglik += 5; System.out.println(isim + " uyudu. Sağlık: " + saglik); } }
Üst sınıf Hayvan: bütün hayvanlarda ortak olan nitelikler ve davranışlar.
public class Kopek extends Hayvan { public Kopek(String isim, int yas) { super(isim, yas); // üst sınıf yapıcısı alanları doldurur } @Override public void konus() { // miras alınan davranışı değiştirir System.out.println(getIsim() + " havlar."); } public void topOyna() { // yalnızca Kopek'te olan davranış System.out.println(getIsim() + " top oynuyor!"); } }
Kopek kopek = new Kopek("Karabaş", 4); kopek.konus(); // Kopek'in sürümü kopek.topOyna(); // Kopek'e özgü kopek.uyu(); // Hayvan'dan miras
Karabaş havlar. Karabaş top oynuyor! Karabaş uyudu. Sağlık: 105.0
Alt sınıf Kopek yalnızca farkı yazar; uyu() hiç yazılmadığı hâlde çalışır.
Hayvan Örneği · Kodu adım adım çalıştır
Hangi Metot Çalışır?
new Kedi("Mavi"): nesne oluşur. İçinde Hayvan'dan gelen isim ve saglik alanları da vardır.
kedi.konus(): arama nesnenin sınıfı Kedi'de başlar. konus() orada var: geçersiz kılınmış sürüm seçilir.
getIsim() Hayvan'dan miras; private isim'e onun aracılığıyla ulaşılır.
kedi.avlan(): Kedi'ye özgü metot; Kedi'de bulunur.
avlan() gövdesi çalışır ve ikinci satır yazılır.
kedi.yemekYe(5.0): Kedi'de yok → bir üst sınıfa, Hayvan'a bakılır ve orada bulunur.
Miras alınan metot, aynı nesnenin saglik alanını günceller: 100.0 + 5.0.
Sonuç yazılır. Kural: metot önce nesnenin kendi sınıfında, yoksa yukarı doğru üst sınıflarda aranır.
class Hayvan { private String isim; private double saglik = 100.0; Hayvan(String isim) { this.isim = isim; } String getIsim() { return isim; } void konus() { System.out.println("Ses yok."); } void yemekYe(double m) { saglik += m; System.out.println(isim + ": " + saglik); } } class Kedi extends Hayvan { Kedi(String isim) { super(isim); } @Override void konus() { System.out.println(getIsim() + " miyavlar."); } void avlan() { System.out.println(getIsim() + " avlandı!"); } } Kedi kedi = new Kedi("Mavi"); // main kedi.konus(); kedi.avlan(); kedi.yemekYe(5.0);
Hayvan Örneği
Kalıtımın Avantajları
Üst sınıfın metot ve nitelikleri alt sınıfta yeniden yazılmadan kullanılır.
Mevcut sınıf, kodu değiştirilmeden yeni özelliklerle genişletilir.
Üst sınıfın metotları alt sınıfta geçersiz kılınarak (overriding) değiştirilebilir.
public class GelismisHesapMakinesi extends HesapMakinesi { // Yeni yetenek: üs alma public double us(double taban, int us) { double sonuc = 1.0; for (int i = 0; i < us; i++) { sonuc *= taban; } return sonuc; } // faktoriyel(int) benzer biçimde eklenir } // main içinde GelismisHesapMakinesi h = new GelismisHesapMakinesi(); System.out.println(h.topla(5, 3)); // 8.0 (miras) System.out.println(h.hafizayiGoruntule()); // 8.0 (miras) System.out.println(h.us(2, 5)); // 32.0 (yeni)
Yapıcılar ve super
super Anahtar Kelimesi
super(...): alt sınıfın yapıcısı içinde üst sınıfın yapıcısını çağırır; üst sınıfın niteliklerine ilk değerleri o atar.super(...)yapıcının ilk satırı olmalıdır.- Yazılmazsa derleyici gizlice
super();(parametresiz) ekler. super.metot(): üst sınıfın metoduna nokta (.) ile erişir; geçersiz kılınmış bir metodun içinden üst sınıfın sürümünü çağırmak için kullanılır.- İlke: her sınıf yalnızca kendi verilerini yönetmelidir. Kedi, Hayvan'ın
isimalanına kendisi atama yapmaz; işisuper(isim)'e bırakır.
class Kedi extends Hayvan { private boolean evcil; Kedi(String isim, boolean evcil) { super(isim); // Hayvan(String) this.evcil = evcil; // kendi verisi } @Override public String toString() { return super.toString() // Hayvan'ınki + ", Evcil: " + evcil; } } // main içinde System.out.println(new Kedi("Mavi", true));
Çıktı
İsim: Mavi, Sağlık: 100.0, Evcil: true
Hayvan'ın toString() metodu isim ve sağlık bilgisini döndürür; Kedi yalnızca kendi alanını ekler.
Yapıcılar ve super · Kodu adım adım çalıştır
Yapıcı Zinciri: new Kedi("Mavi", true)
new: önce bellekte nesneye yer ayrılır; tüm alanlar (Hayvan'ınkiler dahil) varsayılan değerleri alır.
Kedi yapıcısı çağrılır. Kendi işine başlamadan önce üst sınıf kısmı hazırlanmalıdır.
super(isim): Hayvan yapıcısı çağrılır; Kedi yapıcısı bekler.
Hayvan da önce kendi üst sınıfını çağırır: Object(). Her zincir Object'te biter.
Object() döndü. Hayvan kendi alanını doldurur: isim = "Mavi".
saglik = 100.0.
Hayvan yapıcısı mesajını yazar ve döner: önce üst sınıf yazdı.
Kedi yapıcısı kaldığı yerden devam eder: evcil = true.
Kedi yapıcısı mesajını yazar.
Yapıcı bitti; nesnenin adresi kedi değişkenine atanır.
Yapıcılar yukarıdan aşağıya tamamlanır: Object → Hayvan → Kedi.
class Hayvan { private String isim; private double saglik; Hayvan(String isim) { super(); // Object() çağrılır this.isim = isim; saglik = 100.0; System.out.println("Hayvan yapıcısı"); } } class Kedi extends Hayvan { private boolean evcil; Kedi(String isim, boolean evcil) { super(isim); this.evcil = evcil; System.out.println("Kedi yapıcısı"); } } // main içinde Kedi kedi = new Kedi("Mavi", true); System.out.println("Nesne hazır");
Yapıcılar ve super
Gizli super() ve Hatalar
1) Üst sınıfta parametresiz yapıcı yok
class Hayvan { private String isim; Hayvan(String isim) { this.isim = isim; } } class Kedi extends Hayvan { Kedi(String isim) { // derleyici buraya super(); ekler System.out.println("Kedi"); } }
error: constructor Hayvan in class Hayvan cannot be applied to given types; required: String found: no arguments
2) super(...) ilk satırda değil
Kedi(String isim) {
System.out.println("Kedi");
super(isim);
}error: call to super must be first statement in constructor
super(isim);Hiç yapıcı yazılmamış sınıfa derleyici parametresiz bir varsayılan yapıcı (default constructor) ekler; bir yapıcı yazıldığı anda bu eklenmez.
Geçersiz Kılma
Metodu Geçersiz Kılma
Geçersiz kılma (overriding): alt sınıfın, üst sınıftan miras aldığı bir metodu aynı imzayla yeniden yazarak kendi davranışını vermesidir.
- Ad ve parametre listesi aynı olmalı.
- Dönüş türü aynı (veya onun alt türü) olmalı.
- Erişim daraltılamaz:
publicmetotpublickalmalı. final,staticveprivatemetotlar geçersiz kılınamaz.
class Sekil { public void ciz() { System.out.println("Şekil çiziliyor."); } } class Dikdortgen extends Sekil { @Override public void ciz() { System.out.println("Dikdörtgen çiziliyor."); } } // main içinde new Sekil().ciz(); new Dikdortgen().ciz();
Şekil çiziliyor. Dikdörtgen çiziliyor.
// alt sınıfta: void ciz() error: ciz() in Dikdortgen cannot override ciz() in Sekil attempting to assign weaker access privileges; was public
// alt sınıfta: public int ciz() error: ciz() in Dikdortgen cannot override ciz() in Sekil return type int is not compatible with void
Geçersiz Kılma
Geçersiz Kılma ve Aşırı Yükleme
| Geçersiz kılma (overriding) | Aşırı yükleme (overloading) | |
|---|---|---|
| Nerede? | Alt sınıfta, miras alınan metot için | Aynı sınıfta (veya alt sınıfta) |
| Ad | Aynı | Aynı |
| Parametreler | Aynı | Farklı (sayı ya da tür) |
| Dönüş türü | Aynı veya alt türü | Serbest |
| Amaç | Miras alınan davranışı değiştirmek | Aynı işi farklı girdilerle yapmak |
| Seçim zamanı | Çalışma zamanı (nesnenin gerçek türü) | Derleme zamanı (argüman türleri) |
class Dikdortgen extends Sekil { @Override public void ciz() { ... } // geçersiz kılma public void ciz(String renk) { ... } // aşırı yükleme }
d.ciz("Mavi") çıktısı
Mavi dikdörtgen çiziliyor.
Her iki kavram da bir sonraki bölümün konusu olan çok biçimliliğin (polymorphism) temelidir.
Geçersiz Kılma
@Override Etiketi
@Overridebir etikettir (annotation): metodun, üst sınıftan miras alınan bir metodu geçersiz kıldığını bildirir.- Derleyiciye bunu kontrol etmesini söyler: üst sınıfta böyle bir metot yoksa derleme hatası verir.
- Kodu daha okunabilir yapar; diğer geliştiricilere metodun üst sınıftan geldiğini gösterir.
- Zorunlu değildir, ama her zaman yazılması önerilir: yazım hatalarını hemen yakalar.
public class Dikdortgen extends Sekil { // miras alınan metodu geçersiz kıl @Override public void ciz() { System.out.println("Dikdörtgen çiziliyor."); } }
Yazım hatası: Ciz (büyük C)
@Override public void Ciz() { ... }
error: method does not override or implement a method from a supertype
@Override olmasaydı Ciz() sessizce yeni bir metot olurdu ve ciz() çağrıları hâlâ Sekil'in sürümünü çalıştırırdı.
Erişim ve Sınırlama
protected Erişim Seviyesi
| Belirteç | Aynı sınıf | Aynı paket | Alt sınıf (başka paket) | Her yer |
|---|---|---|---|---|
private | ✓ | ✗ | ✗ | ✗ |
| (belirteç yok: paket) | ✓ | ✓ | ✗ | ✗ |
protected | ✓ | ✓ | ✓ | ✗ |
public | ✓ | ✓ | ✓ | ✓ |
public: sınıfın üyelerine her yerden erişilebilir.private: yalnızca o sınıfın içinden.protected: ikisinin arasında bir düzeydir. Sınıfın kendisi, alt sınıfları ve aynı paketteki diğer sınıflar erişebilir.- Bir sınıfın
privateniteliklerine alt sınıf, yalnızca üst sınıftan miras alınanpublicveyaprotectedmetotlar aracılığıyla erişebilir.
İyi uygulama: nitelikler yine private kalsın; alt sınıfların ihtiyaç duyduğu işlemler protected metotlar olarak açılsın.
Erişim ve Sınırlama
protected: Kod Örneği
package canli; public class Hayvan { protected String isim; // alt sınıflar private double saglik; // yalnızca Hayvan public Hayvan(String isim) { this.isim = isim; saglik = 100.0; } public double getSaglik() { return saglik; } protected void saglikEkle(double miktar) { saglik += miktar; } }
package evcil; // başka paket import canli.Hayvan; public class Kedi extends Hayvan { public Kedi(String isim) { super(isim); } public void uyu() { // protected alan: izin var System.out.println(isim + " uyuyor."); // saglik += 5; // private: hata saglikEkle(5); // protected metot System.out.println("Sağlık: " + getSaglik()); } }
new Kedi("Mavi").uyu(); çıktısı
Mavi uyuyor. Sağlık: 105.0
Yorum satırı açılırsa
error: saglik has private access in Hayvan
Erişim ve Sınırlama
final ile Kalıtımı Sınırlamak
finalanahtar kelimesi kalıtımı sınırlamak için kullanılabilir.- Bir metot
finaltanımlanırsa hiçbir alt sınıfta geçersiz kılınamaz (override). - Bir sınıf
finaltanımlanırsa ondan hiçbir alt sınıf türetilemez. Örnek:String,Math,Integer.
class Hayvan { public final void nefesAl() { ... } } class Kedi extends Hayvan { public void nefesAl() { ... } }
error: nefesAl() in Kedi cannot override nefesAl() in Hayvan overridden method is final
final class Sabit { ... } class Deneme extends Sabit { }
error: cannot inherit from final Sabit
String değiştirilemez olmalıdır; bir alt sınıf bu sözü bozamasın.Değişkenlerde final başka bir anlam taşır: değer bir kez atanır (sabit).
Erişim ve Sınırlama
Nesnenin Görünümünü Kısıtlama
- Bir nesne, üst sınıf türünde bir değişkene atanabilir (yukarı dönüşüm, upcasting): her Lastik bir Parça'dır.
- Böylece dışarıya yalnızca üst sınıfa ait metotlar açılır.
- Nesnenin gerçek sınıfına bakılmaksızın, değişkenin türü neyi çağırabileceğimizi belirler.
Parca p = new Lastik("Petlas", "XYZ-123", "225/45R17", true); System.out.println(p.seriNumarasi()); // izin verilir → XYZ-123 // p.kislikMi() // izin verilmez
error: cannot find symbol symbol: method kislikMi() location: variable p of type Parca
Lastik'e özgü metoda ulaşmak için önce tür kontrolü, sonra aşağı dönüşüm (downcasting) gerekir: instanceof slaytına bakın.
Sınıflar Arası İlişkiler
is-a ve has-a İlişkileri
Is-a (kalıtım, inheritance)
- Bir sınıfın başka bir sınıftan türetilmesidir; türetilen sınıf üst sınıfın bir türüdür.
- Alt sınıf nesnesi, üst sınıfın nesnesi gibi de kullanılabilir.
Has-a (oluşum, composition)
- Bir sınıfın başka bir sınıf türünde nitelik içermesidir.
- Nesne, içinde diğer nesnelere referanslar tutar.
// Is-a ilişkisi (kalıtım) public class Araba extends Arac { // Has-a ilişkisi (oluşum) private Motor motor; public Araba(int beygirGucu) { motor = new Motor(beygirGucu); } public void yolaCik() { motor.calistir(); // Motor'a devret hizlan(50); // Arac'tan miras System.out.println("Hız: " + hiz + " km/sa"); } } // Motor: beygirGucu alanı ve calistir(): // "Motor çalıştı: " + beygirGucu + " BG"
new Araba(110).yolaCik();
Motor çalıştı: 110 BG Hız: 50 km/sa
Sınıflar Arası İlişkiler
Çoklu Kalıtım
- Java'da doğrudan çoklu kalıtım desteklenmez: bir sınıf yalnızca bir sınıftan türeyebilir.
- Elmas problemi (diamond problem): B ve C
yaz()'ı farklı geçersiz kılarsa D hangisini almalı? - Birden fazla sınıfın özellikleri gerekiyorsa: oluşum (composition) ve arayüzler (interface; bir sınıf birçok arayüz uygulayabilir, ayrıntısı “Soyut Sınıflar” bölümünde).
class D extends B, C { } // geçersiz
error: '{' expectedinterface Sarj { void sarjEt(); } class ElektrikliAraba extends Araba implements Sarj { @Override public void sarjEt() { System.out.println("Şarj ediliyor."); } }
Sınıflar Arası İlişkiler
Kalıtımla Tasarım İlkeleri
“Her X bir Y midir?” cümlesi doğru değilse kalıtım kullanmayın. Araba bir Motor değildir; Motor'a sahiptir → oluşum.
Üst sınıfın alanlarına super(...) ve üst sınıfın metotlarıyla değer verin; alanları private tutun.
toString ve equals (ve onunla birlikte hashCode) her anlamlı sınıfta geçersiz kılınmalıdır.
Alt sınıfların ortak kavramları soyut (abstract) sınıflarla temsil edilmelidir: “Hayvan” tek başına nesne olmamalıysa.
Object Sınıfı
Object Sınıfı
- Her sınıf
java.lang.Objectsınıfından türer;extendsyazılmamışsa dolaylı olarak. - Bu yüzden her nesnede aşağıdaki metotlar hazır bulunur.
- Varsayılan sürümleri genellikle işimize yaramaz; anlamlı sınıflarda geçersiz kılınırlar.
class Nokta { } // derleyicinin gördüğü: class Nokta extends Object { }
| Metot | Varsayılan davranış |
|---|---|
String toString() | Sınıf adı + @ + hashCode değerinin onaltılık (hex) yazımı |
boolean equals(Object o) | Referansları karşılaştırır: this == o |
int hashCode() | Nesneye özgü bir tamsayı (genellikle her nesnede farklı) |
Class getClass() | Nesnenin çalışma zamanındaki sınıfı (final; geçersiz kılınamaz) |
Object Sınıfı
toString Metodu
public String toString(): nesneyi metin olarak gösterir.println(nesne)ve"..." + nesneonu kendiliğinden çağırır.- Geçersiz kılınmazsa sınıf adı ve nesnenin hashCode değerini içeren bir dize döner.
Geçersiz kılınmadan
class Nokta { private int x, y; Nokta(int x, int y) { this.x = x; this.y = y; } } // main içinde System.out.println(new Nokta(3, 4));
Nokta@28a418fc
@ sonrası değer her çalıştırmada değişebilir; okunaklı değildir.
Geçersiz kılınarak
class Nokta { private int x, y; Nokta(int x, int y) { this.x = x; this.y = y; } @Override public String toString() { return "Nokta[x=" + x + ", y=" + y + "]"; } } // main içinde Nokta n = new Nokta(3, 4); System.out.println(n); System.out.println("Konum: " + n);
Nokta[x=3, y=4] Konum: Nokta[x=3, y=4]
Object Sınıfı · Kodu adım adım çalıştır
== mi, equals mı?
new bir nesne oluşturur; k1 onun adresini (referansını) tutar.
İkinci new: içeriği aynı, ama ayrı bir nesne. k2 onu gösterir.
k3 = k1 nesne kopyalamaz; yalnızca adresi kopyalar. k1 ve k3 aynı nesneyi gösterir.
== referansları karşılaştırır: k1 ve k2 farklı nesneleri gösterir → false.
k1 ve k3 aynı nesneyi gösterir → true.
equals, Kisi'de geçersiz kılındığı için içeriği (ad, yas) karşılaştırır → true. Geçersiz kılınmasaydı false olurdu.
Kisi k1 = new Kisi("Ali", 25); Kisi k2 = new Kisi("Ali", 25); Kisi k3 = k1; System.out.println(k1 == k2); System.out.println(k1 == k3); System.out.println(k1.equals(k2));
Object Sınıfı
equals Metodu
public boolean equals(Object other): iki nesnenin eşdeğer olup olmadığını söyler.- Varsayılan olarak yalnızca referansları karşılaştırır: geçersiz kılınmazsa
==operatörü gibi davranır. - Geçersiz kılınarak davranışı değiştirilir: metot iki nesnenin durumunu (alanlarını) karşılaştırmalı ve eşitse
truedönmelidir. - Parametre
Objecttüründedir; hatalı durumları engellemek için önce tür kontrolü yapılmalıdır.
equals sözleşmesi
| Yansıma | x.equals(x) → true |
| Simetri | x.equals(y) ⇔ y.equals(x) |
| Geçişme | x = y ve y = z ise x = z |
| Tutarlılık | Alanlar değişmedikçe sonuç değişmez |
| null | x.equals(null) → false |
String karşılaştırmasında da kural aynıdır: s1 == s2 değil, s1.equals(s2).Object Sınıfı
instanceof Operatörü
- Bir nesnenin belirli bir sınıfa veya arayüze uyup uymadığını kontrol eder.
- Kullanım:
nesne instanceof Tür; sonuçtrueveyafalse. - Alt sınıf nesnesi, üst sınıfın da örneğidir.
nullbir nesne kabul edilmez:null instanceof Türher zamanfalsedöner. Bu yüzdeninstanceofayrıca null kontrolü gerektirmez.- Aşağı dönüşümden (downcasting) önce kullanılır; yanlış dönüşüm çalışma zamanında
ClassCastExceptionfırlatır.
Exception in thread "main" java.lang.ClassCastException: class Parca cannot be cast to class Lastik
Parca p = new Lastik("Petlas", "XYZ-123", "225/45R17", true); if (p instanceof Lastik) { Lastik l = (Lastik) p; // güvenli dönüşüm System.out.println(l.kislikMi()); } System.out.println(p instanceof Parca); System.out.println(p instanceof Object); Parca bos = null; System.out.println(bos instanceof Parca); Parca duz = new Parca("Bosch", "ABC-9"); System.out.println(duz instanceof Lastik);
true true true false false
Java 16+: örüntü eşleme
if (p instanceof Lastik l) { // kontrol + dönüşüm System.out.println(l.kislikMi()); }
Object Sınıfı
equals Metodunu Yazmak
instanceof ile tür kontrolü
public boolean equals(Object nesne) { if (nesne instanceof Nokta) { // nesne bir Nokta nesnesidir; // dönüştürüp karşılaştır Nokta diger = (Nokta) nesne; return x == diger.x && y == diger.y; } else { // nesne bir Nokta değildir; // eşit olamaz return false; } }
- Parametre türü
Objectolmalıdır;equals(Nokta n)yazmak geçersiz kılma değil, aşırı yüklemedir. - Dönüşüm (
(Nokta) nesne) yalnızca tür kontrolünden sonra güvenlidir.
Deneme
Nokta a = new Nokta(3, 4); Nokta b = new Nokta(3, 4); System.out.println(a == b); System.out.println(a.equals(b)); System.out.println(a.equals("3,4")); System.out.println(a.equals(null));
false true false false
"3,4" bir Nokta değildir → false. null instanceof Nokta da false olduğu için ayrı bir null kontrolüne gerek kalmaz.Object Sınıfı
getClass() ile equals
public class Kisi { private String ad; private int yas; // ... yapıcı ... @Override public boolean equals(Object obj) { // aynı referanssa eşittir if (this == obj) return true; // null ya da farklı sınıf: eşit değil if (obj == null || getClass() != obj.getClass()) return false; // alanları karşılaştır Kisi kisi = (Kisi) obj; return yas == kisi.yas && ad.equals(kisi.ad); } }
this == obj: aynı nesneyse hementrue(hızlı yol).getClass()nesnenin gerçek sınıfını verir; iki tarafın sınıfı birebir aynı olmalıdır.- Temel türler (
int yas)==ile, nesne türündeki alanlar (String ad)equalsile karşılaştırılır.
| Tür kontrolü | Alt sınıf nesnesi eşit sayılabilir mi? |
|---|---|
instanceof | Evet (Kedi nesnesi bir Hayvan'dır) |
getClass() | Hayır (sınıflar birebir aynı olmalı) |
Object Sınıfı
equals ve hashCode
equals geçersiz kılınıyorsa hashCode da geçersiz kılınmalıdır. Eşit nesnelerin hashCode değerleri aynı olmalıdır.import java.util.Objects; public class Nokta { private int x, y; public Nokta(int x, int y) { this.x = x; this.y = y; } @Override public boolean equals(Object o) { return (o instanceof Nokta n) && x == n.x && y == n.y; } @Override public int hashCode() { return Objects.hash(x, y); } @Override public String toString() { return "Nokta[x=" + x + ", y=" + y + "]"; } }
Neden? HashSet ve HashMap önce hashCode ile “kova” seçer, sonra equals çağırır. hashCode farklıysa eşit nesneler hiç karşılaştırılmaz.
HashSet<Nokta> kume = new HashSet<>(); kume.add(new Nokta(3, 4)); kume.add(new Nokta(3, 4)); System.out.println(kume.size() + " " + kume.contains(new Nokta(3, 4)));
| Nokta sınıfında | Çıktı |
|---|---|
yalnızca equals | 2 false ✗ |
equals + hashCode | 1 true ✓ |
o instanceof Nokta n örüntü eşlemesi Java 16+ özelliğidir; klasik biçim önceki slayttaki gibidir.
Özet
Özet
| Kavram | Özü |
|---|---|
| Kalıtım | class Alt extends Ust; alt sınıf üst sınıfın üyelerini miras alır, yenilerini ekler (is-a) |
| Miras alınmayan | Yapıcılar; private üyeler nesnede vardır ama doğrudan erişilemez |
super | super(...): üst sınıf yapıcısı (ilk satır); super.m(): üst sınıfın sürümü |
| Yapıcı zinciri | Object → … → Ust → Alt sırasıyla tamamlanır |
| Geçersiz kılma | Aynı imza, alt sınıfta yeni gövde; @Override ile derleyici denetler |
protected | Sınıf + alt sınıflar + aynı paket |
final | Metot: geçersiz kılınamaz; sınıf: alt sınıfı olamaz |
| Has-a | Oluşum: başka sınıf türünde nitelik; çoklu kalıtım yerine oluşum ve arayüzler |
| Object | Her sınıfın atası; toString, equals, hashCode geçersiz kılınır |
== / equals | Referans karşılaştırma / içerik karşılaştırma |
Özet
Sık Yapılan Hatalar
Üst sınıfta parametresiz yapıcı yoksa: constructor Hayvan in class Hayvan cannot be applied to given types.
saglik += 5; alt sınıfta: saglik has private access in Hayvan. Getter veya protected metot kullanın.
Parametre Object değilse aşırı yüklemedir; @Override ile: method does not override or implement a method from a supertype.
İçerikleri aynı iki nesne için == → false. String dahil, equals kullanın.
Derleme hatası yoktur ama HashSet/HashMap yanlış çalışır: aynı nokta iki kez eklenir.
class D extends B, C → '{' expected. Oluşum veya arayüz kullanın.
public void ciz() alt sınıfta void ciz() olursa: attempting to assign weaker access privileges.
(Lastik) p, p bir Lastik değilse: ClassCastException. Önce instanceof.
Özet
Örnek Problemler
class A { A() { System.out.println("A"); } void yaz() { System.out.println("A.yaz"); } } class B extends A { B() { System.out.println("B"); } @Override void yaz() { System.out.println("B.yaz"); } } class C extends B { C() { super(); System.out.println("C"); } @Override void yaz() { super.yaz(); System.out.println("C.yaz"); } }
C c = new C();ne yazdırır?- Ardından
c.yaz();ne yazdırır? A a = new B(); a.yaz();ne yazdırır?c instanceof Anedir?equals'ı geçersiz kılmayan birOgrencisınıfında, aynı adlı iki nesne içino1.equals(o2)nedir?
Cevapları göster
- A B C: yapıcılar üstten alta tamamlanır (B'nin gizli
super()'ı önce A'yı çalıştırır). - B.yaz, sonra C.yaz:
super.yaz()B'nin sürümünü çağırır. - A B, sonra B.yaz: değişken A türünde ama nesne B olduğu için B'nin sürümü çalışır.
- true: C, B üzerinden A'dan türer.
- false: Object'in
equals'ı referansları karşılaştırır.
Özet
Alıştırmalar
Calisan(ad,maas) ve ondan türeyenYonetici(prim) yazın;toplamGelir()vesuper.toString()kullanan birtoString()ekleyin.Hayvan'ın tek yapıcısıHayvan(String isim).Kus(String isim, boolean ucabilir)yapıcısını yazın.Ogrenci(int no,String ad) içinequalsvehashCodeyazın.- Başka paketteki, alt sınıf olmayan bir sınıf
protectedbir alana erişebilir mi? - is-a mı, has-a mı? Öğrenci–Kişi, Araba–Tekerlek, Kütüphane–Kitap, Kare–Şekil.
Cevaplar / ipuçları
- Yapıcı:
super(ad, maas); this.prim = prim;·toplamGelir():getMaas() + prim.new Yonetici("Ayşe", 50000, 8000)→ 58000.0. Kus(String isim, boolean ucabilir) { super(isim); this.ucabilir = ucabilir; }if (!(o instanceof Ogrenci)) return false; Ogrenci d = (Ogrenci) o; return no == d.no && ad.equals(d.ad);·return Objects.hash(no, ad);- Hayır: protected = sınıf + aynı paket + alt sınıflar.
- is-a: Öğrenci–Kişi, Kare–Şekil · has-a: Araba–Tekerlek, Kütüphane–Kitap.
Özet
Kaynaklar
- Oracle, The Java Tutorials: Inheritance; Overriding and Hiding Methods; Using the Keyword super; Object as a Superclass.
- J. Gosling ve diğ., The Java Language Specification, Java SE 21 Edition (8.1.4 Superclasses and Subclasses, 8.4.8 Inheritance, Overriding, and Hiding).
- P. Deitel ve H. Deitel, Java: How to Program, 11. baskı, Pearson (Bölüm 9: Object-Oriented Programming: Inheritance).
- K. Sierra ve B. Bates, Head First Java, 3. baskı, O'Reilly (Bölüm 7: Inheritance and Polymorphism).
- C. S. Horstmann, Core Java, Volume I: Fundamentals, 12. baskı, Pearson (Bölüm 5: Inheritance).
- J. Bloch, Effective Java, 3. baskı, Addison-Wesley (Madde 10–11: equals ve hashCode; Madde 18: oluşumu kalıtıma tercih edin).