Java birden fazla kalıtıma izin vermez, ancak birden fazla arabirimin uygulanmasına izin verir. Neden?
Java birden fazla kalıtıma izin vermez, ancak birden fazla arabirimin uygulanmasına izin verir. Neden?
Yanıtlar:
Arabirimler sadece belirtmek Çünkü neyi sınıf değildir, yapıyor nasıl bunu yapıyor.
Çoklu kalıtımla ilgili sorun, iki sınıfın aynı şeyi yapmanın farklı yollarını tanımlayabilmesidir ve alt sınıf hangisini seçeceğini seçemez.
Üniversite eğitmenlerimden biri bana şöyle açıkladı:
Bir Toaster olan bir sınıfım ve NuclearBomb olan başka bir sınıfım olduğunu varsayalım. İkisinin de bir "karanlık" ayarı olabilir. Her ikisinin de on () yöntemi vardır. (Birinin bir off () vardır, diğeri yoktur.) Bunların her ikisinin de bir alt sınıfı olan bir sınıf oluşturmak istersem ... gördüğünüz gibi, bu gerçekten yüzümde patlayabilecek bir sorun .
Yani ana konulardan biri, iki ana sınıfınız varsa, aynı özelliğin farklı uygulamalarına sahip olabilirler - veya eğitmenimin örneğindeki gibi aynı ada sahip iki farklı özelliğe sahip olabilirler. O zaman alt sınıfınızın hangisini kullanacağına karar vermek zorundasınız. Bunu ele almanın yolları var, kesinlikle - C ++ bunu yapıyor - ancak Java tasarımcıları bunun çok karmaşık olacağını düşünüyor.
Bununla birlikte, bir arayüzle, başka bir sınıfın bir şey yapma yöntemini ödünç almak yerine sınıfın yapabileceği bir şeyi açıklıyorsunuz. Birden çok arabirimin, çözülmesi gereken zor çakışmalara neden olması, birden çok üst sınıftan daha az olasıdır.
Kalıtım sen bile fazla kullanılırsa Çünkü olamaz demek "Hey, yöntem yararlıdır görünüyor, ben de bu sınıfı genişletir edeceğiz".
public class MyGodClass extends AppDomainObject, HttpServlet, MouseAdapter,
AbstractTableModel, AbstractListModel, AbstractList, AbstractMap, ...
Bu sorunun cevabı, java derleyicisinin iç çalışmasında yatıyor (oluşturucu zinciri). Java derleyicisinin dahili çalışmasını görürsek:
public class Bank {
public void printBankBalance(){
System.out.println("10k");
}
}
class SBI extends Bank{
public void printBankBalance(){
System.out.println("20k");
}
}
Bu derlemeden sonra şöyle görünür:
public class Bank {
public Bank(){
super();
}
public void printBankBalance(){
System.out.println("10k");
}
}
class SBI extends Bank {
SBI(){
super();
}
public void printBankBalance(){
System.out.println("20k");
}
}
sınıfı genişletip onun bir nesnesini yarattığımızda, bir kurucu zincir Objectsınıfa kadar çalışır .
Yukarıdaki kod iyi çalışır. ancak, adı verilen başka bir sınıfımız ve Carşu adla adlandırılan Bankbir karma (çoklu kalıtım) sınıfı varsa SBICar:
class Car extends Bank {
Car() {
super();
}
public void run(){
System.out.println("99Km/h");
}
}
class SBICar extends Bank, Car {
SBICar() {
super(); //NOTE: compile time ambiguity.
}
public void run() {
System.out.println("99Km/h");
}
public void printBankBalance(){
System.out.println("20k");
}
}
Bu durumda (SBICar) yapıcı zinciri oluşturamaz ( derleme zamanı belirsizliği ).
Arabirimler için buna izin verilir, çünkü onun bir nesnesini oluşturamayız.
Yeni konsept defaultve staticyöntem için lütfen arayüzde varsayılana bakın .
Umarım bu sorunuzu çözer. Teşekkürler.
Birden çok arayüz uygulamak çok faydalıdır ve dil uygulayıcılarına veya programcılara fazla sorun yaratmaz. Böylece izin verilir. Çoklu kalıtım da faydalı olsa da, kullanıcılara ciddi sorunlara neden olabilir (korkunç ölüm elması ). Ve çoklu kalıtımla yaptığınız çoğu şey kompozisyon veya iç sınıflar kullanılarak da yapılabilir. Dolayısıyla, birden fazla mirasın kazançlardan daha fazla sorun getirmesi yasaktır.
ToyotaCarve HybridCarher ikisi de türetilmiş Carve geçersiz kılınmışsa ve her ikisi de miras alınmış ancak geçersiz kılmamışsa Car.Drive, sistemin sanalın ne yapması gerektiğini belirleyemez. Arabirimler yukarıdaki italik durumdan kaçınarak bu sorunu önler. PriusCarDriveCar.Drive
void UseCar(Car &foo); arasındaki anlam ayrımı dahil etmek beklenemez ToyotaCar::Driveve HybridCar::Drive(o diğer türleri bile genellikle ne bilmeli beri ne de bakımı var ). Bir dil, C ++ 'ın yaptığı gibi, ToyotaCar &myCaronu geçmek isteyen kodun UseCarönce HybridCarveya birine yayınlanmasını gerektirebilir ToyotaCar, ancak ((Araba) (HybridCar) myCar) .Drive` olduğundan ve ((Car)(ToyotaCar)myCar).Drive farklı şeyler yapacağından kimlik koruyucu değildi.
Bu sorgu için doğru cevabı çoklu miras hakkındaki oracle dokümantasyon sayfasında bulabilirsiniz
Birden çok durum mirası: Alanları birden çok sınıftan devralma yeteneği
Java programlama dilinin birden fazla sınıfı genişletmenize izin vermemesinin bir nedeni, birden fazla sınıftan alan devralma yeteneği olan çoklu durum miras sorunlarından kaçınmaktır
Birden fazla devralmaya izin verilirse ve bu sınıfı örnekleyerek bir nesne oluşturduğunuzda, bu nesne sınıfın tüm üst sınıflarından alanlarını devralır. İki soruna neden olacaktır.
Birden çok uygulama devralma: Birden çok sınıftan yöntem tanımlarını devralma yeteneği
Bu yaklaşımla ilgili sorunlar: çatışmaları ve belirsizliği adlandırın . Bir alt sınıf ve üst sınıf aynı yöntem adını (ve imzasını) içeriyorsa, derleyici hangi sürümü çağıracağını belirleyemez.
Ancak java, Java 8 sürümünden beri tanıtılan varsayılan yöntemlerle bu tür çoklu kalıtım türlerini destekler . Java derleyicisi, belirli bir sınıfın hangi varsayılan yöntemi kullandığını belirlemek için bazı kurallar sağlar.
Elmas probleminin çözümü hakkında daha fazla bilgi için aşağıdaki SE yazısına bakın:
Java 8'deki soyut sınıflar ve arayüzler arasındaki farklar nelerdir?
Birden fazla tür mirası: Bir sınıfın birden fazla arabirim uygulama yeteneği.
Arayüz değiştirilebilir alanlar içermediğinden, burada çoklu durum mirasından kaynaklanan sorunlar hakkında endişelenmenize gerek yoktur.
Nesne durumunun, içindeki alanlara göre atıfta bulunduğu ve çok fazla sınıfın miras alınması durumunda belirsiz hale geleceği söylenir. Bağlantı burada
http://docs.oracle.com/javase/tutorial/java/IandI/multipleinheritance.html
Java, yalnızca arabirimler aracılığıyla birden fazla kalıtımı destekler. Sınıf herhangi bir sayıda arabirim uygulayabilir, ancak yalnızca bir sınıfı genişletebilir.
Ölümcül elmas sorununa yol açtığı için çoklu kalıtım desteklenmez. Bununla birlikte, çözülebilir, ancak karmaşık bir sisteme yol açar, bu nedenle Java kurucuları tarafından birden fazla miras bırakılır.
Şubat 1995'te James Gosling'in “Java: Genel Bakış” başlıklı beyaz kitabında ( link ), Java'da çoklu kalıtımın neden desteklenmediği hakkında bir fikir verilmektedir.
Gosling'e göre:
"JAVA, C ++ 'ın deneyimlerimize faydadan daha fazla keder getiren nadiren kullanılan, az anlaşılmış, kafa karıştırıcı birçok özelliği atlıyor. Bu öncelikle operatör aşırı yüklemesi (yöntem aşırı yüklemesine rağmen), çoklu kalıtım ve kapsamlı otomatik zorlamalardan oluşuyor."
Aynı nedenden ötürü C #, birden fazla kalıtsallığa izin vermez, ancak birden çok arabirim uygulamanızı sağlar.
C ++ 'dan çoklu kalıtımla alınan ders, değerinden daha fazla soruna yol açmasıydı.
Arayüz, sınıfınızın uygulamak zorunda olduğu şeylerin bir sözleşmesidir. Arayüzden herhangi bir işlevsellik kazanmazsınız. Miras, bir üst sınıfın işlevselliğini miras almanıza izin verir (ve çoklu mirasta, bu son derece kafa karıştırıcı olabilir).
Birden fazla arabirime izin vermek, birden fazla kalıtım kullanarak çözebileceğiniz aynı sorunları çözmek için Tasarım Desenlerini (Adaptör gibi) kullanmanıza izin verir, ancak çok daha güvenilir ve öngörülebilir bir şekilde.
D1ve D2hem miras Bve her geçersiz kılma fonksiyonu fve eğer objbir tür bir örneği olan S, hem devralır D1ve D2ancak geçersiz kılmaz f, daha sonra bir referans döküm Siçin D1bir şey verim gereken fkullanımlar D1geçersiz kılma ve döküm Bolmamalıdır değiştir şunu. Aynı şekilde bir başvuru döküm Siçin D2olan bir şey vermelidir fkullanımları D2geçersiz kılma ve döküm Bolduğunu değiştirmemelidir. Bir dilin sanal üyelerin eklenmesine izin vermesi gerekmiyorsa ...
Bu konu yakın olmadığından bu yanıtı göndereceğim, umarım bu java'nın neden birden fazla kalıtıma izin vermediğini anlamasına yardımcı olur.
Aşağıdaki sınıfı düşünün:
public class Abc{
public void doSomething(){
}
}
Bu durumda Abc sınıfı hiçbir şeyi doğru uzatmıyor mu? Çok hızlı değil, bu sınıf örtük nesnesi sınıf genişletir, temel sınıf her şeyin java çalışmasına izin verir. Her şey bir nesnedir.
Eğer IDE gibi yöntemleri kullanmak için izin göreceksiniz yukarıdaki sınıfını kullanmayı denerseniz: equals(Object o), toString(), vs, ama bu yöntemleri beyan etmedi, onlar temel sınıftan çıktıObject
Deneyebilirsiniz:
public class Abc extends String{
public void doSomething(){
}
}
Bu iyidir, çünkü sınıfınız örtük Objectolmayacak, ancak Stringsöylediğiniz için uzayacaktır . Aşağıdaki değişikliği düşünün:
public class Abc{
public void doSomething(){
}
@Override
public String toString(){
return "hello";
}
}
Şimdi toString () öğesini çağırırsanız sınıfınız her zaman "merhaba" döndürür.
Şimdi aşağıdaki sınıfı hayal edin:
public class Flyer{
public void makeFly(){
}
}
public class Bird extends Abc, Flyer{
public void doAnotherThing(){
}
}
Yine sınıf Flyerörtülü yöntemi vardır Nesne uzanır toString()hepsi uzanır beri, herhangi bir sınıf bu yöntemi olacak Objectböylece, dolaylı olarak çağırırsanız, toString()gelen Birdhangi toString()kullanım olurdu java? Kimden Abcveya Flyer? Bu, iki veya daha fazla sınıfı genişletmeye çalışan herhangi bir sınıfta gerçekleşecek, bu tür "yöntem çarpışması" ndan kaçınmak için arayüz fikrini inşa ettiler , temelde onları dolaylı olarak Nesneyi dolaylı olarak genişletmeyen soyut bir sınıf olarak düşünebilirsiniz . Bunlar olduğu soyut bunlar aşağıdakilerden biri olan bir sınıfı tarafından uygulanacak gerekecektir nesne (yalnızca bir arabirimi örnekleyemezsiniz, bunlar bir sınıf tarafından uygulanmalıdır), bu yüzden her şey iyi çalışmaya devam edecektir.
Arabirimlerden sınıfları farklı için, anahtar kelime uygular sadece arayüzleri için ayrıldı.
Varsayılan olarak hiçbir şeyi genişletmediği için aynı sınıfta istediğiniz herhangi bir arabirimi uygulayabilirsiniz (ancak başka bir arabirimi genişleten bir arabirim oluşturabilirsiniz, ancak yine "baba" arabirimi Nesneyi genişletmez), bu nedenle arabirim sadece bir arayüz ve onlar " yöntemleri imza sütunları " muzdarip olmaz , derleyici yaparsanız size bir uyarı atar ve sadece düzeltmek için yöntem imza değiştirmek zorunda kalacak (imza = yöntem adı + params + dönüş tipi) .
public interface Flyer{
public void makeFly(); // <- method without implementation
}
public class Bird extends Abc implements Flyer{
public void doAnotherThing(){
}
@Override
public void makeFly(){ // <- implementation of Flyer interface
}
// Flyer does not have toString() method or any method from class Object,
// no method signature collision will happen here
}
Çünkü bir arayüz sadece bir sözleşmedir. Ve bir sınıf aslında veri için bir kaptır.
Örneğin, m1 () yöntemine sahip iki A, B sınıfı. Ve C sınıfı hem A, B'yi uzatır.
class C extends A, B // for explaining purpose.
Şimdi, C sınıfı m1 tanımını arayacaktır. İlk olarak, bulamazsa sınıfta arayacak ve daha sonra ebeveyn sınıfına bakacaktır. Hem A, B tanımına sahiptir Yani burada tanımın seçilmesi gereken belirsizlik oluşur. Bu yüzden JAVA ÇOKLU MİRASI DESTEKLEMEZ.
Java, iki nedenden ötürü birden fazla kalıtım özelliğini desteklemez:
Object . Birden fazla süper sınıftan miras alındığında, alt sınıf Object sınıfının özelliğini edinme belirsizliğini kazanır.super()supper class yapıcısını çağırmaya çağırıyor. Sınıfın birden fazla süper sınıfı varsa, kafası karışır.Yani bir sınıf birden fazla süper sınıftan uzandığında derleme zamanı hatası alırız.
Örneğin, Sınıf A'nın bir getSomething yöntemine ve Sınıf B'nin bir getSomething yöntemine sahip olduğu ve sınıf C'nin A ve B'yi genişlettiği durumu ele alalım. Hangi yöntemi arayacağınızı belirlemenin bir yolu yoktur.
Arayüzler temel olarak sadece bir uygulayıcı sınıfın hangi yöntemleri içermesi gerektiğini belirtir. Birden fazla arabirim uygulayan bir sınıf, sınıfın tüm bu arabirimlerdeki yöntemleri uygulaması gerektiği anlamına gelir. Whci, yukarıda açıklanan herhangi bir soruna yol açmaz.
Test1, Test2 ve Test3'ün üç sınıf olduğu bir senaryo düşünün. Test3 sınıfı, Test2 ve Test1 sınıflarını devralır. Test1 ve Test2 sınıfları aynı yönteme sahipse ve bunu alt sınıf nesnesinden çağırırsanız, Test1 veya Test2 sınıfının yöntemini çağırmak için bir belirsizlik olacaktır, ancak arabirimde herhangi bir uygulama olmadığı için arabirimde böyle bir belirsizlik yoktur.
Java, belirsizlik sorunu nedeniyle çoklu kalıtım, çoklu yol ve karma kalıtım desteklemez:
Scenario for multiple inheritance: Let us take class A , class B , class C. class A has alphabet(); method , class B has also alphabet(); method. Now class C extends A, B and we are creating object to the subclass i.e., class C , so C ob = new C(); Then if you want call those methods ob.alphabet(); which class method takes ? is class A method or class B method ? So in the JVM level ambiguity problem occurred. Thus Java does not support multiple inheritance.
Referans Bağlantısı: https://plus.google.com/u/0/communities/102217496457095083679
basit bir şekilde hepimizin bildiği gibi, bir sınıfı devralabilir (genişletebilir), ancak çok fazla arabirim uygulayabiliriz, çünkü arabirimlerde sadece bir işlevsellik söylemiyoruz. java çok sınıf genişletebilir ve bu aynı yöntemlere sahip varsayalım varsayalım .. bu noktada alt sınıf süper sınıf yöntemi çağırmak için çalışırsanız hangi yöntem çalıştırmak için varsayalım ??, derleyici karışık örnek olsun : - birden fazla genişletmeye çalışın ama arayüzler bu yöntemler alt sınıfta uygulamanız gereken organları yok .. birden fazla uygulama için deneyin endişe yok ..
* Bu, Java'da yeni başlayan biri olduğum için basit bir cevaptır *
Üç sınıf vardır düşünün X, Yve Z.
Bu yüzden X extends Y, Z
Ve her ikisi gibi miras alıyoruz Yve aynı dönüş türüne ve argümanlarına Zsahip bir yöntem alphabet()var. Bu yöntem alphabet()de Ydiyor ilk alfabe görüntülemek ve yöntem alfabe Zdiyor ekran son alfabesi . İşte alphabet()çağrıldığında belirsizlik geliyor X. İlk veya son alfabeyi görüntüleyip görüntülemeyeceği ??? Dolayısıyla java birden fazla mirası desteklemiyor. Arayüzler söz konusu olduğunda, Yve Zarayüz olarak düşünün . Yani her ikisi de yöntem bildirimini içerecek, alphabet()ancak tanımı içermeyecektir . İlk alfabeyi mi, son alfabeyi mi yoksa herhangi bir şey mi görüntüleyeceğini söylemez, sadece bir yöntem beyan ederalphabet(). Yani belirsizliği yükseltmek için bir sebep yok. Yöntemi sınıf içinde istediğimiz her şeyle tanımlayabiliriz X.
Yani bir kelimeyle, Arayüzlerde tanım uygulamadan sonra yapılır, bu yüzden karışıklık olmaz.