İçeriğe geç

Polimorfizm ve Dinamik Bağlama — Kararı Kim Veriyor?

Orta 8 dk Çok sık karşılaşılır

Önce şunu oku: Kalıtım ve Kompozisyon — Kimin İç Ayrıntısına Bağlısın?

30 saniyede özet

Aynı çağrı nesneye göre farklı iş yapabilir; buna polimorfizm denir. Ama her karar çalışırken verilmez: aşırı yükleme, static metotlar ve alanlar derlerken sabitlenir. İkisini karıştırmak sessiz hatalar doğurur.

İki noktanın eşit olup olmadığını söyleyen bir equals yazdın, ama iki eşit nokta bir kümeye ikisi birden girdi. Metot doğru, karşılaştırma doğru — ama hiç çağrılmıyor. Sebep: yazdığın şey bir override değil, bir overload.

  1. Bayt: İki eşit nokta kümeye ikisi birden girdi! equals'ım doğru ama hiç çağrılmıyor.

  2. Sen: Nasıl yani, metot orada duruyor.

  3. Bayt: Duruyor. Ama belki eskisini değiştirmedin, yanına yeni bir metot yazdın.

  4. Bayt: Menüden seçim mi, vardiyadaki kişi mi? Kararı kimin verdiğine bakalım.

Aynı çağrı, farklı davranış

polimorfizmAynı çağrının, nesnenin gerçek tipine göre farklı davranış üretmesi. Java'da override edilmiş örnek metotlarıyla sağlanır.Sözlükte gör →, aynı çağrının karşısındaki nesneye göre farklı iş yapmasıdır. shape.area() yazan kod, karşısında daire mi kare mi olduğunu bilmez; alanı doğru hesaplamak nesnenin kendi işidir.

Java bunu dinamik bağlamaÇağrılacak metodun sürümünün derleme anında değil, çalışma anında nesnenin gerçek sınıfına bakılarak seçilmesi.Sözlükte gör → ile yapar. Program çalışırken JVM nesnenin gerçek sınıfına bakar ve o sınıfın yazdığı sürümü çağırır.

Kafam karıştı, daha basit anlat

Bir kumandada tek bir “aç” tuşu var. Televizyona basarsan ekran, klimaya basarsan fan açılır. Tuş aynı, işi yapan karşısındaki cihaz.

Hızlı kontrolBaşlangıç

`Animal a = new Dog(); a.sound();` — Dog, sound()'u override ediyor. Hangi sürüm çalışır?

Cevabı biliyor musun?Önce birini seç. Tekrar zamanlaması buna göre ayarlanıyor.

@Override anotasyonu ne işe yarar?

Cevabı biliyor musun?Önce birini seç. Tekrar zamanlaması buna göre ayarlanıyor.

Kim, ne zaman karar veriyor?

describe(Object) ve describe(String) var. Object value = "merhaba"; describe(value) hangisini çağırır? Cevabı göster

describe(Object). overloadingAynı adlı, farklı parametre listeli metotlar. Hangisinin çağrılacağına derleyici, argümanların bildirilen tiplerine bakarak karar verir.Sözlükte gör → seçimi derleme anında, argümanın bildirilen tipine göre yapılır. Nesnenin String olması fark etmez.

Menü derlerken seçilir, telefonu açan kişi çalışırken belli olur.
Adım adım oku
  1. describe(value) derlenirken derleyici değişkenin yazılı tipine bakar: Object. Menüden describe(Object) seçilir.
  2. Çalışırken nesnenin aslında bir String olduğu anlaşılır, ama overload seçimi çoktan yapılmıştır; değişmez.
  3. s.area() ise bir override'dır: JVM çalışırken nesnenin gerçek sınıfına bakar ve Circle'ın area'sını çağırır.
  4. Özet: overload derleme anında değişkenin tipine göre, override çalışma anında nesnenin sınıfına göre seçilir.
ErişimKarar ne zamanNeye göre
Override edilmiş örnek metoduÇalışma anıNesnenin gerçek sınıfı
Aşırı yüklenmiş metotDerleme anıArgümanların bildirilen tipi
Static metotDerleme anıDeğişkenin bildirilen tipi
AlanDerleme anıDeğişkenin bildirilen tipi

Tablodaki dört satırdan yalnızca ilki çalışırken karar verir. Geri kalan her şeyi derleyici, sen programı çalıştırmadan önce sabitler.

Bankada ikisi de karşına çıkar. Havale masrafı kanala göre değişir; override sayesinde servis hangi kanalda olduğunu bilmeden doğru masrafı alır. Bloke IBAN listesinde ise overload edilmiş bir equals, bloke hesaba para gönderilmesine göz yumar.

Derinleş · Havale masrafı ve bloke IBAN: override mı, overload mı? 4 dosya · ~100 satır · ilk okumada atlayabilirsin
Proje dosyaları

src/main/java/com/bank/transfer/ FeePolicy.java Masraf politikası: her kanal kendi hesabını yapar. sealed, izin verilen kanalları tek yerde sayar.

src/main/java/com/bank/transfer/FeePolicy.java
// One implementation per channel. Amounts come from the tariff config, not from code.
public sealed interface FeePolicy permits FastFee, EftFee, SwiftFee {
BigDecimal feeFor(BigDecimal amount);
}
// Instant transfer: one flat fee.
record FastFee(BigDecimal flat) implements FeePolicy {
@Override
public BigDecimal feeFor(BigDecimal amount) {
return flat;
}
}
// Same-day interbank transfer: flat fee, waived for a premium segment.
record EftFee(BigDecimal flat, boolean premium) implements FeePolicy {
@Override
public BigDecimal feeFor(BigDecimal amount) {
return premium ? BigDecimal.ZERO : flat;
}
}
// International transfer: a percentage with a floor.
record SwiftFee(BigDecimal rate, BigDecimal minimum) implements FeePolicy {
@Override
public BigDecimal feeFor(BigDecimal amount) {
return amount.multiply(rate).setScale(2, RoundingMode.HALF_UP).max(minimum);
}
}

src/main/java/com/bank/transfer/ TransferService.java Havale servisi: politikanın hangi kanal olduğunu bilmez. Doğru feeFor çalışırken nesnenin sınıfına göre seçilir.

src/main/java/com/bank/transfer/TransferService.java
@Service
class TransferService {
private final FeePolicies policies; // picks the policy for a channel and customer
private final BlockedIbans blocked;
private final Ledger ledger;
TransferService(FeePolicies policies, BlockedIbans blocked, Ledger ledger) {
this.policies = policies;
this.blocked = blocked;
this.ledger = ledger;
}
@Transactional
public TransferReceipt send(TransferRequest request) {
if (blocked.contains(request.beneficiary())) {
throw new BlockedBeneficiaryException(request.beneficiary());
}
FeePolicy policy = policies.forChannel(request.channel(), request.customerNo());
// No switch on the channel: the JVM calls the feeFor of the object's real class.
BigDecimal fee = policy.feeFor(request.amount());
return ledger.post(request, fee);
}
}

src/main/java/com/bank/transfer/ Iban.java IBAN: equals(Object) gerçekten override edilmiş, hashCode da onunla uyumlu. Küme ve map onu doğru bulur.

src/main/java/com/bank/transfer/Iban.java
public final class Iban {
private final String value;
public Iban(String raw) {
// "TR33 0006 1005 ..." and "tr330006 1005..." are the same account.
this.value = raw.replace(" ", "").toUpperCase(Locale.ROOT);
}
// Object, not Iban: this replaces Object.equals, so HashSet and HashMap call it.
@Override
public boolean equals(Object other) {
return other instanceof Iban iban && value.equals(iban.value);
}
@Override
public int hashCode() {
return value.hashCode();
}
@Override
public String toString() {
return value;
}
}

src/main/java/com/bank/transfer/ BrokenIban.java Karşı örnek: equals(BrokenIban) bir overload. HashSet onu hiç çağırmaz; bloke IBAN listede olsa da bulunamaz.

src/main/java/com/bank/transfer/BrokenIban.java
// Counter-example. It looks right and its unit test passes:
// new BrokenIban("TR33...").equals(new BrokenIban("TR33...")) is true.
public final class BrokenIban {
private final String value;
public BrokenIban(String raw) {
this.value = raw.replace(" ", "").toUpperCase(Locale.ROOT);
}
// An overload, not an override: the parameter is BrokenIban, not Object.
// Set.contains calls equals(Object), which is still Object's identity check,
// so a blocked IBAN read fresh from a request is never found in the set.
public boolean equals(BrokenIban other) {
return other != null && value.equals(other.value);
}
@Override
public int hashCode() {
return value.hashCode();
}
}
Kafam karıştı, daha basit anlat

Program çalışırken yalnızca bir karar verilir: nesnenin gerçek sınıfına göre hangi metodun çalışacağı. Aynı isimli metotlardan hangisinin seçileceğine derleyici önceden karar verir.

Hızlı kontrolOrta

Program ne yazdırır?

Cevabı biliyor musun?Önce birini seç. Tekrar zamanlaması buna göre ayarlanıyor.
Overload.java
1static String describe(Object o) { return "Object"; }
2static String describe(String s) { return "String"; }
3
4Object value = "merhaba";
5System.out.println(describe(value));
Java 21UTF-8LF

`Animal a = new Dog();` ile yapılan her erişim için seçim ne zaman yapılır?

Cevabı biliyor musun?Önce birini seç. Tekrar zamanlaması buna göre ayarlanıyor.

Sınıflandırılmamış

Çalışma anında, nesneye göre

Dinamik bağlama

    Derleme anında, bildirilen tipe göre

    Statik bağlama

      Kendin gör

      Polimorfizm — hangi sürüm, ne zaman seçilir?

      Tohum 709163
      Dispatch.java
      1class Animal {
      2 String name = "hayvan";
      3 Animal() { describe(); }
      4 void describe() { }
      5 String sound() { return "..."; }
      6 static String kind() { return "Animal"; }
      7}
      8class Dog extends Animal {
      9 String name = "köpek";
      10 private String label = "Karabaş";
      11 @Override void describe() { System.out.println(label.length()); }
      12 @Override String sound() { return "Hav"; }
      13 static String kind() { return "Dog"; }
      14}
      15class Printer {
      16 String print(Animal x) { return "print(Animal)"; }
      17 String print(Dog x) { return "print(Dog)"; }
      18}
      19
      20Animal a = new Dog();
      21System.out.println(a.sound());
      Java 21UTF-8LF
      1. Oynat ya da adımla.
      Hız
      Adım 0

      Şu an ne oldu?

      Animal a = new Dog();

      a.sound() çağrılacak. Nesne her durumda bir Dog.

      Görevler0/3

      • Animal değişkeniyle Dog'un sürümünü çalıştıraçık

        İpucu

        Seçimi nesnenin gerçek sınıfı yapan tek tür çağrı hangisi?

      • Nesne Dog olduğu hâlde Animal'ın sürümünü çalıştıraçık

        İpucu

        Derleme anında bağlanan üç şey var.

      • Nesne daha kurulmadan alt sınıfın metodunu çalıştıraçık

        İpucu

        Taban sınıfın constructor'ı override edilebilir bir metot çağırıyor.

      Olay günlüğü (0)

      Henüz olay yok. Oynat veya adımla.

      1. Varsayılanla oynat. Animal değişkeni, Dog nesnesi: “Hav”.
      2. “Static metot” seç. Aynı nesne, “Animal” — derleyici seçti.
      3. “Alan” seç, sonra değişkeni Dog yap. Farklı değişken, farklı alan.
      4. “Constructor’dan…” seç. NullPointerException.
      Hızlı kontrolİleri

      `Animal a = new Dog(); System.out.println(a.name);` — iki sınıfta da `name` alanı var. Ne yazdırılır ve neden?

      Cevabı biliyor musun?Önce birini seç. Tekrar zamanlaması buna göre ayarlanıyor.

      Satır satır: constructor’daki tuzak

      Nesne bitmeden alt sınıfın kodu

      Dog.java
      1class Animal {
      2 Animal() { describe(); }
      3 void describe() { }
      4}
      5class Dog extends Animal {
      6 private String label = "Karabaş";
      7 @Override void describe() { System.out.println(label.length()); }
      8}
      9
      şu an çalışan satırnew Dog();

      Debug

      Adım 1/4

      JVM Dog nesnesi için bellek ayrıldı; bütün alanlar varsayılan değerinde.

      label
      = null
      Java 21UTF-8LF10:1

      Sol/sağ ok tuşlarıyla da gezebilirsin.

      Constructor’dan, alt sınıfın değiştirebileceği bir metodu çağırma. Alt sınıfın alanları henüz hazır değilken onun kodu çalışır. Yardımcı metodu private, final ya da static yap ki değiştirilemesin.

      Kafam karıştı, daha basit anlat

      Ev daha kurulmadan içine eşya taşımaya benzer. Üst sınıfın constructor’ı alt sınıfın metodunu çağırırsa, alt sınıfın alanları henüz boştur.

      Hızlı kontrolOrta

      Animal'ın constructor'ı override edilebilir `describe()` metodunu çağırıyor. Dog bu metodu override edip kendi `label` alanını okuyor. `new Dog()` ne olur?

      Cevabı biliyor musun?Önce birini seç. Tekrar zamanlaması buna göre ayarlanıyor.

      Tuzaklar

      equals(Point) yazmak. Parametre tipi farklı olduğu için bu, Object.equals(Object)’in yerine geçmez; yanına ikinci bir metot ekler. Koleksiyonlar senin metodunu hiç çağırmaz.

      @Override’ı yazmamak. Bu etiket “ben bir metodun yerine geçiyorum” demektir; yanılıyorsan derleyici hemen uyarır.

      Uzun instanceof zincirleri. Nesneye tipini sormak yerine davranışı sınıfların kendisine taşı; bütün durumları derleyiciye kontrol ettirmek istersen sealed + switch kullan.

      Aynı adlı alanlar. Alt sınıfta aynı adla bir alan tanımlamak üsttekini değiştirmez, ikinci bir alan yaratır. Hangisini okuduğun, değişkenin tipine bağlıdır.

      Hızlı kontrolOrta

      İki eşit Point bir HashSet'e konuyor ve set iki eleman içeriyor. `set.contains(new Point(1, 2))` de false dönüyor. Hangi satır?

      Cevabı biliyor musun?Önce birini seç. Tekrar zamanlaması buna göre ayarlanıyor.

      Hatalı satıra dokun, sonra kontrol et.

      Point.java
      Java 21UTF-8LF

      Kendini sına

      Şimşek turu1/5

      Override edilen bir metodun hangi sürümünün çalışacağına çalışma anında karar verilir.

      Soru 1/2Orta

      Bir metotta `if (shape instanceof Circle) ... else if (shape instanceof Square) ...` zinciri var ve her yeni şekil eklendiğinde buraya dal ekleniyor. Polimorfizmle nasıl düzeltilir?

      Cevabı biliyor musun?Önce birini seç. Tekrar zamanlaması buna göre ayarlanıyor.

      Aklında kalacak üç şey

      1. 1 Override edilmiş bir metotta hangi kodun çalışacağını nesnenin gerçek sınıfı seçer. Değişkenin tipi yalnızca çağrının yazılabilir olup olmadığını belirler.
      2. 2 Aşırı yükleme, static metotlar ve alanlar derleme anında, yazılan tipe göre bağlanır. Bunlar polimorfik değildir.
      3. 3 Constructor içinden override edilebilir bir metot çağırmak, alt sınıfın kodunu alanları hazır olmadan çalıştırır.
      Sonraki kapı Bir hesap nesnesini yazdırdın ve ekrana Hesap@1b6d3586 çıktı. Bu garip yazı nereden geldi? Object Sınıfı — Her Nesnenin Ortak Mirası · 8 dk

      3 kart sonraki derste seni bekliyor

      0/5 kart bu dersten toplandı

      Bu dersin üstüne kurulanlar

      Bunlar bu dersi temel alıyor; hazır olduğunda devam edebilirsin.