Neden Çoklu Sınıf Kalıtımı Yok?
Coddy'nin Java Journey'sinin Nesne Yönelimli Programlama bölümünün bir parçası — ders 26 / 87.
Java, bir sınıfın birden fazla sınıfı genişletmesini kasten engeller. Bu kısıtlama, Diamond Problem olarak bilinen bir sorun nedeniyle mevcuttur.
Java'nın çoklu kalıtıma izin verdiğini hayal edin. Şu varsayımsal senaryoyu düşünün:
// Bu kod Java'da geçerli DEĞİLDİR
public class A {
public void greet() {
System.out.println("Hello from A");
}
}
public class B extends A {
@Override
public void greet() {
System.out.println("Hello from B");
}
}
public class C extends A {
@Override
public void greet() {
System.out.println("Hello from C");
}
}
// Java'da izin verilmez!
public class D extends B, C { }Bir D nesnesi üzerinde greet() metodunu çağırdıysanız, hangi sürüm çalışmalı? B'den gelen mi yoksa C'den gelen mi? Bu belirsizlik, kalıtım diyagramının oluşturduğu elmas şeklinden adını alan Elmas Problemi'dir (Diamond Problem).
Java'nın çözümü basittir: sınıfların yalnızca tekli kalıtımına izin verir. Ancak, Java bir alternatif sunar. Bir sınıf, gelecek bir bölümde öğreneceğiniz birden fazla arayüzü uygulayabilir.
Arayüzler elmas problemini farklı şekilde çözer ve size belirsizlik olmadan esneklik sağlar.
// Bu Java'da geçerlidir
public class Dog extends Animal implements Runnable, Comparable<Dog> {
// Birden fazla arayüz uygulanabilir
}Bu tasarım tercihi, Java'nın kalıtım modelini temiz ve öngörülebilir tutarken, arayüzler aracılığıyla güçlü kod yeniden kullanımına olanak tanır.
Görev
KolayJava'nın tekli kalıtım (single inheritance) kuralını gösteren ve bu kısıtlama dahilinde nasıl hala esnek tasarımlar elde edebileceğinizi gösteren bir müzik çalar sistemi oluşturalım.
Hem bir müzik çaların hem de bir sesli asistanın özelliklerini birleştiren akıllı bir hoparlör oluşturmak istediğinizi hayal edin. Java birden fazla sınıfı genişletmeye (extending multiple classes) izin vermediğinden, hiyerarşinizi tekli kalıtım kullanarak dikkatli bir şekilde tasarlamanız gerekecektir.
Kodunuzu düzenlemek için dört dosya oluşturacaksınız:
AudioDevice.java: Tüm ses çalan cihazların paylaştığı temel sınıfı oluşturun. Şunlara sahip olmalıdır:deviceName(String) için özel (private) bir alan- Cihaz adını kabul eden bir yapıcı (constructor)
- Adı döndüren bir
getDeviceName()metodu - Şunu yazdıran bir
playSound()metodu:[deviceName]: Playing audio
MusicPlayer.java: AudioDevice sınıfını genişleten ve müziğe özgü özellikler ekleyen bir sınıf oluşturun:currentSong(String) için özel (private) bir alan- Cihaz adını alan ve
super(deviceName)kullanan bir yapıcı - Mevcut şarkıyı ayarlayan bir
setSong(String song)metodu - Şunu yazdırmak için
playSound()metodunu geçersiz kılın (override):[deviceName]: Now playing - [currentSong]
SmartSpeaker.java: MusicPlayer sınıfını genişleten bir sınıf oluşturun (hem MusicPlayer hem de bir VoiceAssistant sınıfını değil - bu çoklu kalıtım olurdu!). Akıllı hoparlör, ses özellikleri ekleyerek müzik çalar üzerine inşa edilir:assistantName(String) için özel (private) bir alan- Cihaz adını ve asistan adını alan,
super(deviceName)kullanan bir yapıcı - Şunu yazdıran bir
voiceCommand(String command)metodu:[assistantName]: Processing "[command]" - Şunu yazdıran bir
getFullInfo()metodu:[deviceName] with [assistantName] assistant
Main.java: Çok seviyeli kalıtım zincirinizi (multilevel inheritance chain) gösterin. Üç girdi alacaksınız: bir cihaz adı (String), bir asistan adı (String) ve bir şarkı adı (String). Bir SmartSpeaker oluşturun, bir şarkı ayarlayın ve ardından şu metodları sırasıyla çağırın:getFullInfo()playSound()voiceCommand("skip to next")
Üç girdi alacaksınız: cihaz adı, asistan adı ve şarkı adı.
SmartSpeaker'ın, ilgisiz birden fazla sınıfı genişletmeye çalışmak yerine, bir zincirleme (AudioDevice -> MusicPlayer -> SmartSpeaker) içinde MusicPlayer'ı genişleterek nasıl müzik yetenekleri kazandığına dikkat edin. Bu, Java'nın kalıtımı temiz ve belirsizlikten uzak tutma yaklaşımıdır!
Kopya kağıdı
Java yalnızca tekli kalıtıma (single inheritance) izin verir - bir sınıf yalnızca başka bir sınıfı genişletebilir. Bu, bir sınıfın birden fazla üst sınıftan aynı metodu miras alması durumunda ortaya çıkan belirsizliği, yani Elmas Problemi'ni (Diamond Problem) önler.
// Java'da izin verilmez - çoklu kalıtım
public class D extends B, C { } // HATA!Ancak Java, bir alternatif olarak bir sınıfın birden fazla arayüzü (interface) uygulamasına izin verir:
// Java'da geçerli
public class Dog extends Animal implements Runnable, Comparable<Dog> {
// Bir sınıfı genişletebilir ve birden fazla arayüzü uygulayabilir
}Java, çok seviyeli kalıtımı (multilevel inheritance) - kalıtım zincirleri oluşturmayı - destekler:
public class AudioDevice { }
public class MusicPlayer extends AudioDevice { }
public class SmartSpeaker extends MusicPlayer { }
// SmartSpeaker hem MusicPlayer hem de AudioDevice'dan miras alırKendin dene
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
// Girdileri oku
String deviceName = scanner.nextLine();
String assistantName = scanner.nextLine();
String songName = scanner.nextLine();
// TODO: deviceName ve assistantName ile bir SmartSpeaker oluşturun
// TODO: setSong() kullanarak şarkıyı ayarlayın
// TODO: getFullInfo() metodunu çağırın
// TODO: playSound() metodunu çağırın
// TODO: voiceCommand("skip to next") metodunu çağırın
}
}
Bu ders kısa bir quiz içerir. Soruları yanıtlamak ve ilerlemeni kaydetmek için derse başla.
Nesne Yönelimli Programlama bölümündeki tüm dersler
1OOP Temelleri
Harici DosyalarOOP'ye GirişSınıflar ve Nesnelerthis Anahtar KelimesiMetotlarAlanlar (Öznitelikler)Yapıcı MetotYapıcı Metot Aşırı YüklemeÖzet - Basit Hesap Makinesi4Kalıtım
Temel Kalıtım (extends)super Anahtar KelimesiMetot Geçersiz Kılma (@Override)Yapıcı Metot ZincirlemeObject SınıfıTekli ve Çok Seviyeli KalıtımNeden Çoklu Sınıf Kalıtımı Yok?Özet - Çalışan Hiyerarşisi7Özel Metotlar ve Object Sınıfı
toString() Metoduequals() ve hashCode()clone() MetoducompareTo() ve ComparableComparator ArayüzüÖzet - Özel Sıralama2Erişim Belirleyiciler ve Kapsülleme
Erişim Seviyelerine Genel BakışGetter ve Setter MetotlarıBilgi Gizlemefinal Anahtar KelimesiÖzet - Banka Hesabı Yöneticisi5Polimorfizm
Metot Aşırı Yükleme TemelleriMetot Geçersiz Kılma (Çalışma Zamanı)Upcasting ve Downcastinginstanceof OperatörüSoyut Sınıflar ve MetotlarÖzet - Şekil Hesaplayıcı8İleri Düzey OOP Kavramları
Kompozisyon vs KalıtımAgregasyon vs KompozisyonDahili, Yuvalanmış ve Anonim SınıflarEnum'lar ve Enum MetotlarıRecords (Java 16+)Sealed Classes (Java 17+)11Tasarım Kalıpları Bölüm 1
Tasarım Kalıplarına GirişSingleton KalıbıFactory KalıbıBuilder KalıbıObserver KalıbıStrategy Kalıbı14Final Meydan Okumaları
E-Öğrenme PlatformuBankacılık SistemiOyun Karakteri GeliştirmeAraç Kiralama Servisi3Sınıf Özellikleri ve Statik Üyeler
Instance ve Statik DeğişkenlerStatik MetotlarStatik BloklarSabitler (static final)Özet - Sayaç ve Utility6Arayüzler ve Soyut Sınıflar
Arayüzlere GirişArayüzleri UygulamaÇoklu Arayüz UygulamaArayüzlerde Default ve StaticSoyut Sınıflar ve ArayüzlerFonksiyonel ArayüzlerÖzet - Ödeme Sistemi9Generics
Generics'e GirişGeneric SınıflarGeneric MetotlarSınırlandırılmış Tip ParametreleriWildcard'lar (?, extends, super)Özet - Generic Container12Tasarım Kalıpları Bölüm 2
Komut KalıbıAdaptör KalıbıDekoratör KalıbıŞablon Metot KalıbıDurum KalıbıKompozit KalıbıYineleyici Kalıbı