Ich habe den Fragentitel bearbeitet, um ihn aussagekräftiger zu gestalten.
Bozho
4
Interessanterweise wird es im JDK 8 Erweiterungsmethoden geben, mit denen die Implementierung von Schnittstellenmethoden definiert werden kann. Regeln wurden Mehrfachvererbung von Verhalten zu regeln definiert, aber nicht des Staates (was ich verstehen , mehr ist problematisch .
Edwin Dalorzo
1
Bevor ihr Zeit mit Antworten verschwendet, die euch nur sagen "Wie Java Mehrfachvererbung erreicht" ... Ich schlage vor, dass ihr zur Antwort von @Prabal Srivastava geht, die euch logischerweise sagt, was intern passieren muss, damit Klassen dieses Recht nicht zulassen. . und erlauben nur Schnittstellen das Recht, Mehrfachvererbung zuzulassen.
Yo Apps
Antworten:
228
Da Schnittstellen nur angeben, was die Klasse tut, nicht wie sie es tut.
Das Problem bei der Mehrfachvererbung besteht darin, dass zwei Klassen unterschiedliche Methoden definieren können, um dasselbe zu tun, und die Unterklasse nicht auswählen kann, welche ausgewählt werden soll.
Ich habe C ++ gemacht und bin einige Male auf genau dasselbe Problem gestoßen. Ich habe kürzlich gelesen, dass Scala "Eigenschaften" hat, die mir wie etwas zwischen der "C ++" - und der "Java" -Methode erscheinen.
Seit Java 8 können Sie zwei identische Standardmethoden definieren, eine in jeder Schnittstelle. Wenn Sie beide Schnittstellen in Ihrer Klasse implementieren, müssen Sie diese Methode in der Klasse selbst überschreiben, siehe: docs.oracle.com/javase/tutorial/java/IandI/…
Bobbel
6
Diese Antwort ist nicht korrekt. Das Problem besteht nicht darin, das Wie anzugeben, und Java 8 soll dies beweisen. In Java 8 können zwei Super-Interfaces dieselbe Methode mit unterschiedlichen Implementierungen deklarieren. Dies ist jedoch kein Problem, da die Interface-Methoden virtuell sind. Sie können sie also einfach überschreiben und das Problem ist behoben. Das eigentliche Problem besteht in der Mehrdeutigkeit der Attribute , da Sie diese Mehrdeutigkeit beim Überschreiben des Attributs nicht lösen können (Attribute sind nicht virtuell).
Alex Oliveira
1
Was meinst du mit "Attribute"?
Bozho
96
Einer meiner Hochschullehrer erklärte es mir folgendermaßen:
Angenommen, ich habe eine Klasse, die ein Toaster ist, und eine andere Klasse, die NuclearBomb ist. Sie könnten beide eine "Dunkelheit" -Einstellung haben. Beide haben eine on () -Methode. (Einer hat ein off (), der andere nicht.) Wenn ich eine Klasse erstellen möchte, die eine Unterklasse von beiden ist ... wie Sie sehen können, ist dies ein Problem, das mir hier wirklich in die Luft jagen könnte .
Eines der Hauptprobleme ist also, dass zwei übergeordnete Klassen möglicherweise unterschiedliche Implementierungen derselben Funktion haben - oder möglicherweise zwei unterschiedliche Funktionen mit demselben Namen, wie im Beispiel meines Lehrers. Dann müssen Sie entscheiden, welche Ihre Unterklasse verwenden wird. Es gibt sicherlich Möglichkeiten, damit umzugehen - C ++ tut dies -, aber die Entwickler von Java waren der Meinung, dass dies die Dinge zu kompliziert machen würde.
Mit einer Schnittstelle beschreiben Sie jedoch etwas, zu dem die Klasse in der Lage ist, anstatt die Methode einer anderen Klasse zu übernehmen, etwas zu tun. Mehrere Schnittstellen verursachen viel seltener schwierige Konflikte, die gelöst werden müssen, als mehrere übergeordnete Klassen.
Danke, NomeN. Die Quelle des Zitats war ein Doktorand namens Brendan Burns, der zu dieser Zeit auch das Open-Source-Quell-Repository von Quake 2 betreute. Stelle dir das vor.
Syntactic
4
Das Problem mit dieser Analogie ist, dass, wenn Sie eine Unterklasse einer Atombombe und eines Toasters erstellen, der "Nuklear-Toaster" bei Verwendung vernünftigerweise explodieren würde.
101100
19
Wenn jemand beschließt, eine Atombombe und einen Toaster zu mischen, hat er es verdient, dass die Bombe in seinem Gesicht explodiert. Das Zitat ist trügerische Argumentation
masoud
1
Dieselbe Programmiersprache erlaubt die mehrfache Vererbung von "Schnittstellen", daher gilt diese "Begründung" nicht.
Neugieriger
24
Da die Vererbung überbeansprucht wird, auch wenn Sie nicht sagen können : "Hey, diese Methode sieht nützlich aus, ich werde diese Klasse auch erweitern."
Können Sie erklären, warum Sie sagen, dass die Vererbung überbeansprucht wird? Eine Gottklasse zu schaffen ist genau das, was ich tun möchte! Ich finde so viele Leute, die sich um die Einzelvererbung kümmern, indem sie "Tools" -Klassen mit statischen Methoden erstellen.
Duncan Calvert
9
@ DuncanCalvert: Nein, das möchten Sie nicht, nicht wenn dieser Code jemals gewartet werden muss. Viele statische Methoden verfehlen den Punkt von OO, aber eine übermäßige Mehrfachvererbung ist viel schlimmer, da Sie völlig den Überblick verlieren, welcher Code wo verwendet wird und was eine Klasse konzeptionell ist. Beide versuchen, das Problem zu lösen: "Wie kann ich diesen Code dort verwenden, wo ich ihn brauche?", Aber das ist ein einfaches kurzfristiges Problem. Das viel schwierigere langfristige Problem, das durch ein korrektes OO-Design gelöst wird, lautet: "Wie kann ich diesen Code ändern, ohne dass das Programm auf unvorhersehbare Weise an 20 verschiedenen Stellen
Michael Borgwardt
2
@DuncanCalvert: und Sie lösen das, indem Sie Klassen mit hoher Kohäsion und geringer Kopplung haben, was bedeutet, dass sie Daten und Code enthalten, die intensiv miteinander interagieren, aber nur über eine kleine, einfache öffentliche API mit dem Rest des Programms interagieren. Dann können Sie über diese API anstelle der internen Details nachdenken, was wichtig ist, da die Benutzer nur eine begrenzte Anzahl von Details gleichzeitig im Auge behalten können.
Michael Borgwardt
18
Die Antwort auf diese Frage liegt in der internen Arbeitsweise des Java-Compilers (Konstruktorverkettung).
Wenn wir die interne Arbeitsweise des Java-Compilers sehen:
Wenn wir die Klasse erweitern und ein Objekt daraus erstellen, wird eine Konstruktorkette bis zur ObjectKlasse ausgeführt.
Der obige Code läuft einwandfrei. aber wenn wir eine andere Klasse haben, Cardie erweitert wird, Bankund eine Hybridklasse (Mehrfachvererbung), die aufgerufen wird SBICar:
classCarextendsBank{Car(){super();}publicvoid run(){System.out.println("99Km/h");}}classSBICarextendsBank,Car{SBICar(){super();//NOTE: compile time ambiguity.}publicvoid run(){System.out.println("99Km/h");}publicvoid printBankBalance(){System.out.println("20k");}}
In diesem Fall kann (SBICar) keine Konstruktorkette erstellen ( Mehrdeutigkeit der Kompilierungszeit ).
Für Schnittstellen ist dies zulässig, da wir kein Objekt daraus erstellen können.
Das Implementieren mehrerer Schnittstellen ist sehr nützlich und verursacht weder Sprachimplementierern noch Programmierern große Probleme. So ist es erlaubt. Mehrfachvererbung ist zwar auch nützlich, kann den Benutzern jedoch ernsthafte Probleme bereiten (gefürchteter Diamant des Todes ). Und die meisten Dinge, die Sie mit Mehrfachvererbung tun, können auch durch Komposition oder unter Verwendung innerer Klassen erledigt werden. Mehrfachvererbung ist daher verboten, da sie mehr Probleme als Gewinne mit sich bringt.
Was ist das Problem mit dem "Diamanten des Todes"?
Neugieriger
2
@curiousguy Enthält mehr als ein Unterobjekt derselben Basisklasse, Mehrdeutigkeit (Überschreiben, von der die Basisklasse verwendet wird), komplizierte Regeln zum Auflösen dieser Mehrdeutigkeit.
Tadeusz Kopec
@curiousguy: Wenn ein Framework vorsieht, dass das Umwandeln einer Objektreferenz in eine Referenz vom Basistyp identitätserhaltend ist, muss jede Objektinstanz genau eine Implementierung einer Basisklassenmethode haben. Wenn ToyotaCarund HybridCarbeide abgeleitet von Carund überschrieben Car.Drive, und wennPriusCar beide geerbt , aber nicht überschrieben werdenDrive , hat das System keine Möglichkeit zu identifizieren, was die virtuelle Car.DrivePerson tun soll. Schnittstellen vermeiden dieses Problem, indem sie den oben kursiven Zustand vermeiden.
Supercat
1
@supercat "Das System hätte keine Möglichkeit zu identifizieren, was das virtuelle Car.Drive tun soll." <- Oder es könnte einfach einen Kompilierungsfehler geben und Sie dazu bringen, einen explizit auszuwählen, wie es C ++ tut.
Chris Middleton
1
@ChrisMiddleton: Eine Methode void UseCar(Car &foo); Es kann nicht erwartet werden, dass eine Disambiguierung zwischen ToyotaCar::Driveund enthalten ist HybridCar::Drive(da es oft weder wissen noch darauf achten sollte, dass diese anderen Typen überhaupt existieren ). Eine Sprache könnte, wie C ++, erfordern, dass der Code ToyotaCar &myCar, an den er übergeben werden soll, UseCarzuerst an entweder HybridCaroder umgewandelt wird ToyotaCar, aber seit ((Car) (HybridCar) myCar) .Drive` und((Car)(ToyotaCar)myCar).Drive verschiedene Dinge tut, was bedeuten würde, dass die Upcasts waren nicht identitätserhaltend.
Supercat
6
Eine genaue Antwort auf diese Frage finden Sie auf der Oracle-Dokumentationsseite zur Mehrfachvererbung
Mehrfache Vererbung des Status: Fähigkeit, Felder von mehreren Klassen zu erben
Ein Grund, warum die Java-Programmiersprache es Ihnen nicht erlaubt, mehr als eine Klasse zu erweitern, besteht darin, die Probleme der Mehrfachvererbung des Status zu vermeiden, dh die Fähigkeit, Felder von mehreren Klassen zu erben
Wenn Mehrfachvererbung zulässig ist und Wenn Sie ein Objekt durch Instanziieren dieser Klasse erstellen, erbt dieses Objekt Felder von allen Oberklassen der Klasse. Es wird zwei Probleme verursachen.
Was ist, wenn Methoden oder Konstruktoren aus verschiedenen Superklassen dasselbe Feld instanziieren?
Welche Methode oder welcher Konstruktor hat Vorrang?
Mehrfachvererbung der Implementierung: Möglichkeit, Methodendefinitionen von mehreren Klassen zu erben
Probleme mit diesem Ansatz: Namenskonflikte und Mehrdeutigkeiten . Wenn eine Unterklasse und eine Oberklasse denselben Methodennamen (und dieselbe Signatur) enthalten, kann der Compiler nicht bestimmen, welche Version aufgerufen werden soll.
Java unterstützt diese Art der Mehrfachvererbung jedoch mit Standardmethoden , die seit der Veröffentlichung von Java 8 eingeführt wurden. Der Java-Compiler bietet einige Regeln, um zu bestimmen, welche Standardmethode eine bestimmte Klasse verwendet.
Weitere Informationen zur Lösung des Diamantproblems finden Sie im folgenden SE-Beitrag:
Mehrfachvererbung des Typs: Fähigkeit einer Klasse, mehr als eine Schnittstelle zu implementieren.
Da die Schnittstelle keine veränderlichen Felder enthält, müssen Sie sich hier keine Gedanken über Probleme machen, die sich aus der Mehrfachvererbung des Status ergeben.
Es wird gesagt, dass der Objektstatus in Bezug auf die darin enthaltenen Felder referenziert wird und es mehrdeutig werden würde, wenn zu viele Klassen geerbt würden. Hier ist der Link
Java unterstützt die Mehrfachvererbung nur über Schnittstellen. Eine Klasse kann eine beliebige Anzahl von Schnittstellen implementieren, jedoch nur eine Klasse erweitern.
Mehrfachvererbung wird nicht unterstützt, da dies zu einem tödlichen Diamantproblem führt. Es kann jedoch gelöst werden, führt jedoch zu einem komplexen System, sodass die Java-Gründer die Mehrfachvererbung verworfen haben.
In einem Whitepaper mit dem Titel "Java: ein Überblick" von James Gosling im Februar 1995 ( Link ) wird eine Vorstellung davon gegeben, warum Mehrfachvererbung in Java nicht unterstützt wird.
Laut Gosling:
"JAVA lässt viele selten verwendete, schlecht verstandene und verwirrende Funktionen von C ++ aus, die unserer Erfahrung nach mehr Kummer als Nutzen bringen. Dies besteht hauptsächlich aus einer Überladung des Bedieners (obwohl es eine Überladung der Methode gibt), einer Mehrfachvererbung und umfangreichen automatischen Zwängen."
Der Link ist nicht zugänglich. Bitte überprüfen und aktualisieren Sie es.
MashukKhan
3
Aus dem gleichen Grund erlaubt C # keine Mehrfachvererbung, aber Sie können mehrere Schnittstellen implementieren.
Die Lehre aus C ++ mit Mehrfachvererbung war, dass es zu mehr Problemen führte, als es wert war.
Eine Schnittstelle ist ein Vertrag über Dinge, die Ihre Klasse implementieren muss. Sie erhalten keine Funktionalität von der Schnittstelle. Durch Vererbung können Sie die Funktionalität einer übergeordneten Klasse erben (und bei Mehrfachvererbung kann dies äußerst verwirrend sein).
Wenn Sie mehrere Schnittstellen zulassen, können Sie Entwurfsmuster (wie den Adapter) verwenden, um dieselben Arten von Problemen zu lösen, die Sie mit Mehrfachvererbung lösen können, jedoch auf eine viel zuverlässigere und vorhersehbarere Weise.
C # hat keine Mehrfachvererbung, gerade weil Java dies nicht zulässt. Es wurde viel später als Java entwickelt. Das Hauptproblem bei der Mehrfachvererbung war meiner Meinung nach die Art und Weise, wie den Menschen beigebracht wurde, sie links und rechts zu verwenden. Das Konzept, dass Delegation in den meisten Fällen eine viel bessere Alternative ist, gab es Anfang und Mitte der neunziger Jahre einfach nicht. Daher erinnere ich mich an Beispiele in Lehrbüchern, in denen Auto ein Rad und eine Tür und eine Windschutzscheibe ist, während Auto Räder, Türen und Windschutzscheibe enthält. Die einzige Vererbung in Java war also eine ruckartige Reaktion auf diese Realität.
Alexander Pogrebnyak
2
@AlexanderPogrebnyak: Wählen Sie zwei der folgenden drei aus: (1) Erlauben Sie identitätserhaltende Casts von einer Subtypreferenz zu einer Supertypreferenz; (2) Erlauben Sie einer Klasse, virtuelle öffentliche Mitglieder hinzuzufügen, ohne abgeleitete Klassen neu zu kompilieren. (3) Ermöglichen Sie einer Klasse, virtuelle Mitglieder implizit von mehreren Basisklassen zu erben, ohne sie explizit angeben zu müssen. Ich glaube nicht, dass es einer Sprache möglich ist, alle drei oben genannten Punkte zu verwalten. Java entschied sich für # 1 und # 2 und C # folgte diesem Beispiel. Ich glaube, dass C ++ nur # 3 übernimmt. Persönlich denke ich, dass # 1 und # 2 nützlicher sind als # 3, aber andere können sich unterscheiden.
Supercat
@supercat "Ich glaube nicht, dass eine Sprache alle drei oben genannten Funktionen verwalten kann" - wenn die Offsets der Datenelemente zur Laufzeit und nicht zur Kompilierungszeit ermittelt werden (wie in Objective-Cs "nicht fragilem ABI" ") und / oder eine Klassenbasis (dh jede konkrete Klasse hat eine eigene Mitglieder-Offset-Tabelle), dann denke ich, dass alle 3 Ziele erreicht werden können.
Das paramagnetische Croissant
@TheParamagneticCroissant: Das größte semantische Problem ist # 1. Wenn D1und D2beide vererben B, und jeder überschreibt eine Funktion f, und wenn objeine Instanz eines Typs ist , Sdie erbt von beiden D1und D2doch überschreibt nicht f, dann einen Verweis Gießen Szu D1sollte etwas , dessen Ausbeute fAnwendungen die D1Überschreibung und dem Gießen Bsollte nicht ändere das. Ebenso Gießen einen Verweis Sauf D2sollte etwas , dessen Ausbeute fAnwendungen die D2Überschreibung und Gießen Bsollte daran nichts ändern. Wenn eine Sprache das
Hinzufügen
1
@TheParamagneticCroissant: Es könnte sein, und meine Auswahlliste wurde etwas vereinfacht, um in einen Kommentar zu passen, aber die Verschiebung der Laufzeit macht es dem Autor von D1, D2 oder S unmöglich zu wissen, welche Änderungen sie vornehmen können, ohne zu brechen Verbraucher ihrer Klasse.
Supercat
2
Da dieses Thema nicht eng ist, werde ich diese Antwort veröffentlichen. Ich hoffe, dies hilft jemandem zu verstehen, warum Java keine Mehrfachvererbung zulässt.
Betrachten Sie die folgende Klasse:
publicclassAbc{publicvoid doSomething(){}}
In diesem Fall erweitert die Klasse Abc nichts richtig? Diese implizite Klasse ist nicht so schnell und erweitert die Klasse Object, die Basisklasse, mit der alles in Java funktioniert. Alles ist ein Objekt.
Wenn Sie versuchen , die Klasse zu verwenden oben sehen Sie , dass Ihre IDE können Sie Methoden verwenden , wie: equals(Object o), toString(), etc, aber du hast nicht die Methoden erklären, kamen sie von der BasisklasseObject
Dies ist in Ordnung, da Ihre Klasse nicht implizit erweitert wird, Objectsondern erweitert wird, Stringweil Sie es gesagt haben. Betrachten Sie die folgende Änderung:
Wieder Klasse FlyerObjekt implizit erstreckt , die das Verfahren hat toString(), wird jede Klasse diese Methode haben , da sie alle sich Objectindirekt, also, wenn Sie rufen toString()aus Bird, die toString()Java verwenden haben würde? Von Abcoder Flyer? Dies geschieht bei jeder Klasse, die versucht, zwei oder mehr Klassen zu erweitern. Um diese Art von "Methodenkollision" zu vermeiden, haben sie die Idee der Schnittstelle erstellt . Grundsätzlich könnte man sie als abstrakte Klasse betrachten, die Object nicht indirekt erweitert . Da sie abstrakt sind, müssen sie von einer Klasse implementiert werden, die ein Objekt ist (Sie können eine Schnittstelle nicht alleine instanziieren, sie muss von einer Klasse implementiert werden), damit alles weiterhin einwandfrei funktioniert.
Um Klassen von Schnittstellen zu unterscheiden, wurde das Schlüsselwort implement nur für Schnittstellen reserviert.
Sie können jede beliebige Schnittstelle in derselben Klasse implementieren, da sie standardmäßig nichts erweitert (Sie können jedoch eine Schnittstelle erstellen, die eine andere Schnittstelle erweitert, aber auch die "Vater" -Schnittstelle würde Object nicht erweitern), also ist eine Schnittstelle Nur eine Schnittstelle, und sie leiden nicht unter " Methodensignaturspaltungen ". Wenn dies der Fall ist , gibt der Compiler eine Warnung an Sie aus und Sie müssen nur die Methodensignatur ändern, um sie zu beheben (Signatur = Methodenname + Parameter + Rückgabetyp). .
publicinterfaceFlyer{publicvoid makeFly();// <- method without implementation}publicclassBirdextendsAbcimplementsFlyer{publicvoid doAnotherThing(){}@Overridepublicvoid makeFly(){// <- implementation of Flyer interface}// Flyer does not have toString() method or any method from class Object, // no method signature collision will happen here}
Die grundlegende Schwierigkeit bei der Mehrfachvererbung besteht in der Möglichkeit, dass eine Klasse ein Mitglied über mehrere Pfade erbt, die es unterschiedlich implementieren, ohne eine eigene übergeordnete Implementierung bereitzustellen. Die Schnittstellenvererbung vermeidet dies, da die einzigen Orte, an denen Schnittstellenmitglieder implementiert werden können, Klassen sind, deren Nachkommen auf die Einzelvererbung beschränkt sind.
Supercat
1
Zum Beispiel zwei Klassen A, B mit derselben Methode m1 (). Und Klasse C erweitert sowohl A als auch B.
class C extends A, B // for explaining purpose.
Jetzt sucht Klasse C nach der Definition von m1. Zuerst wird in der Klasse gesucht, wenn es nicht gefunden wurde, dann wird es in der Elternklasse überprüft. Sowohl A als auch B haben die Definition. Hier tritt also Mehrdeutigkeit auf, welche Definition gewählt werden soll. JAVA UNTERSTÜTZT also NICHT MEHRFACHE ERBUNG.
Wie wäre es, wenn der Java-Compiler den Compiler gibt, wenn die gleichen Methoden oder Variablen in beiden übergeordneten Klassen definiert sind, damit wir den Code ändern können ...
Siluveru Kiran Kumar
1
Java unterstützt aus zwei Gründen keine Mehrfachvererbung:
In Java ist jede Klasse ein Kind der ObjectKlasse. Wenn es von mehr als einer Superklasse erbt, erhält die Unterklasse die Mehrdeutigkeit, die Eigenschaft der Objektklasse zu erwerben.
In Java hat jede Klasse einen Konstruktor, ob wir ihn explizit oder gar nicht schreiben. Die erste Anweisung ruft super()auf, um den Konstruktor der Supper-Klasse aufzurufen. Wenn die Klasse mehr als eine Superklasse hat, wird sie verwirrt.
Wenn sich eine Klasse von mehr als einer Superklasse erstreckt, erhalten wir einen Fehler bei der Kompilierung.
Nehmen wir zum Beispiel den Fall, dass Klasse A eine getSomething-Methode und Klasse B eine getSomething-Methode hat und Klasse C A und B erweitert. Was würde passieren, wenn jemand C.getSomething nennt? Es gibt keine Möglichkeit zu bestimmen, welche Methode aufgerufen werden soll.
Schnittstellen geben im Grunde nur an, welche Methoden eine implementierende Klasse enthalten muss. Eine Klasse, die mehrere Schnittstellen implementiert, bedeutet lediglich, dass die Klasse die Methoden aller dieser Schnittstellen implementieren muss. Whci würde zu keinen Problemen führen, wie oben beschrieben.
" Was würde passieren, wenn jemand C.getSomething anruft? " Es ist ein Fehler in C ++. Problem gelöst.
Neugieriger
Das war der Punkt ... das war ein Gegenbeispiel, das ich für klar hielt. Ich habe darauf hingewiesen, dass es keine Möglichkeit gibt zu bestimmen, welche Methode zum Abrufen von etwas aufgerufen werden soll. Auch als Randnotiz war die Frage im Zusammenhang mit Java nicht C ++
John Kane
Es tut mir leid, dass ich nicht verstehe, worum es Ihnen geht. Offensichtlich gibt es in einigen Fällen Unklarheiten mit MI. Wie ist das ein Gegenbeispiel? Wer hat behauptet, dass MI niemals zu Mehrdeutigkeiten führt? " Auch als Randnotiz bezog sich die Frage auf Java, nicht auf C ++ " Also?
Neugieriger
Ich habe nur versucht zu zeigen, warum diese Mehrdeutigkeit besteht und warum sie nicht mit Schnittstellen zusammenhängt.
John Kane
Ja, MI kann zu mehrdeutigen Anrufen führen. So kann Überlastung. Also sollte Java Überladung entfernen?
Neugieriger
0
Stellen Sie sich ein Szenario vor, in dem Test1, Test2 und Test3 drei Klassen sind. Die Klasse Test3 erbt die Klassen Test2 und Test1. Wenn die Klassen Test1 und Test2 dieselbe Methode haben und Sie sie vom untergeordneten Klassenobjekt aufrufen, besteht eine Mehrdeutigkeit beim Aufrufen der Methode der Klasse Test1 oder Test2, es gibt jedoch keine solche Mehrdeutigkeit für die Schnittstelle, da in der Schnittstelle keine Implementierung vorhanden ist.
Java unterstützt aufgrund von Mehrdeutigkeitsproblemen keine Mehrfachvererbung, Mehrweg- und Hybridvererbung:
Scenariofor multiple inheritance:Let us take class A ,class B ,class C.class A has alphabet(); method ,class B has also alphabet(); method.Nowclass C extends A, B and we are creating object to the subclass i.e.,class C , so C ob =new C();Thenif 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.ThusJava does not support multiple inheritance.
Auf einfache Weise, die wir alle kennen, können wir eine Klasse erben (erweitern), aber wir können so viele Schnittstellen implementieren. Das liegt daran, dass wir in Schnittstellen keine Implementierung geben, sondern nur die Funktionalität. nehmen an, wenn Java kann so viele Klassen erweitert und die haben gleiche Methoden .. in diesem Punkt , wenn wir Superklasse aufzurufen Methode in der Unterklasse , welche Methode annehmen laufen versuchen ??, Compiler verwirren lassen
Beispiel: - Versuchen Sie, um mehr erstreckt
aber in Schnittstellen Diese Methoden haben keine Körper, die wir in der Unterklasse implementieren sollten.
Versuchen Sie, mehrere Implementierungen durchzuführen,
damit Sie sich keine Sorgen machen müssen.
Sie können diese Beispiele einfach hier posten. Ohne das sieht es aus wie ein Textblock auf eine 9 Jahre alte Frage, die hundertmal beantwortet wurde.
Pochmurnik
-1
* Dies ist eine einfache Antwort, da ich ein Anfänger in Java bin *
Bedenken Sie, dass es drei Klassen gibt X, Yund Z.
Wir erben also wie X extends Y, Z
Und beide Yund Zhaben eine Methode alphabet()mit demselben Rückgabetyp und denselben Argumenten. Diese Methode alphabet()in Ysagt, dass das erste Alphabet angezeigt werden soll, und das Methodenalphabet in Zsagt, dass das letzte Alphabet angezeigt werden soll . Hier kommt also Mehrdeutigkeit, wenn von alphabet()aufgerufen wird X. Ob es heißt, erstes oder letztes Alphabet anzuzeigen ??? Java unterstützt also keine Mehrfachvererbung. Bei Schnittstellen betrachten Yund Zals Schnittstellen. Beide enthalten also die Deklaration der Methode, alphabet()aber nicht die Definition. Es wird nicht angegeben, ob das erste oder das letzte Alphabet oder etwas anderes angezeigt werden soll, sondern nur eine Methode deklariertalphabet(). Es gibt also keinen Grund, die Mehrdeutigkeit zu erhöhen. Wir können die Methode mit allem definieren, was wir innerhalb der Klasse wollen X.
Kurz gesagt, in Interfaces erfolgt die Definition nach der Implementierung, also keine Verwirrung.
Antworten:
Da Schnittstellen nur angeben, was die Klasse tut, nicht wie sie es tut.
Das Problem bei der Mehrfachvererbung besteht darin, dass zwei Klassen unterschiedliche Methoden definieren können, um dasselbe zu tun, und die Unterklasse nicht auswählen kann, welche ausgewählt werden soll.
quelle
Einer meiner Hochschullehrer erklärte es mir folgendermaßen:
Eines der Hauptprobleme ist also, dass zwei übergeordnete Klassen möglicherweise unterschiedliche Implementierungen derselben Funktion haben - oder möglicherweise zwei unterschiedliche Funktionen mit demselben Namen, wie im Beispiel meines Lehrers. Dann müssen Sie entscheiden, welche Ihre Unterklasse verwenden wird. Es gibt sicherlich Möglichkeiten, damit umzugehen - C ++ tut dies -, aber die Entwickler von Java waren der Meinung, dass dies die Dinge zu kompliziert machen würde.
Mit einer Schnittstelle beschreiben Sie jedoch etwas, zu dem die Klasse in der Lage ist, anstatt die Methode einer anderen Klasse zu übernehmen, etwas zu tun. Mehrere Schnittstellen verursachen viel seltener schwierige Konflikte, die gelöst werden müssen, als mehrere übergeordnete Klassen.
quelle
Da die Vererbung überbeansprucht wird, auch wenn Sie nicht sagen können : "Hey, diese Methode sieht nützlich aus, ich werde diese Klasse auch erweitern."
quelle
Die Antwort auf diese Frage liegt in der internen Arbeitsweise des Java-Compilers (Konstruktorverkettung). Wenn wir die interne Arbeitsweise des Java-Compilers sehen:
Nach dem Kompilieren sieht dies so aus:
Wenn wir die Klasse erweitern und ein Objekt daraus erstellen, wird eine Konstruktorkette bis zur
Object
Klasse ausgeführt.Der obige Code läuft einwandfrei. aber wenn wir eine andere Klasse haben,
Car
die erweitert wird,Bank
und eine Hybridklasse (Mehrfachvererbung), die aufgerufen wirdSBICar
:In diesem Fall kann (SBICar) keine Konstruktorkette erstellen ( Mehrdeutigkeit der Kompilierungszeit ).
Für Schnittstellen ist dies zulässig, da wir kein Objekt daraus erstellen können.
Für ein neues Konzept
default
und eine neuestatic
Methode verweisen wir bitte auf die Standardeinstellung in der Schnittstelle .Hoffe, dies wird Ihre Frage lösen. Vielen Dank.
quelle
Das Implementieren mehrerer Schnittstellen ist sehr nützlich und verursacht weder Sprachimplementierern noch Programmierern große Probleme. So ist es erlaubt. Mehrfachvererbung ist zwar auch nützlich, kann den Benutzern jedoch ernsthafte Probleme bereiten (gefürchteter Diamant des Todes ). Und die meisten Dinge, die Sie mit Mehrfachvererbung tun, können auch durch Komposition oder unter Verwendung innerer Klassen erledigt werden. Mehrfachvererbung ist daher verboten, da sie mehr Probleme als Gewinne mit sich bringt.
quelle
ToyotaCar
undHybridCar
beide abgeleitet vonCar
und überschriebenCar.Drive
, und wennPriusCar
beide geerbt , aber nicht überschrieben werdenDrive
, hat das System keine Möglichkeit zu identifizieren, was die virtuelleCar.Drive
Person tun soll. Schnittstellen vermeiden dieses Problem, indem sie den oben kursiven Zustand vermeiden.void UseCar(Car &foo)
; Es kann nicht erwartet werden, dass eine Disambiguierung zwischenToyotaCar::Drive
und enthalten istHybridCar::Drive
(da es oft weder wissen noch darauf achten sollte, dass diese anderen Typen überhaupt existieren ). Eine Sprache könnte, wie C ++, erfordern, dass der CodeToyotaCar &myCar
, an den er übergeben werden soll,UseCar
zuerst an entwederHybridCar
oder umgewandelt wirdToyotaCar
, aber seit ((Car) (HybridCar) myCar) .Drive` und((Car)(ToyotaCar)myCar).Drive
verschiedene Dinge tut, was bedeuten würde, dass die Upcasts waren nicht identitätserhaltend.Eine genaue Antwort auf diese Frage finden Sie auf der Oracle-Dokumentationsseite zur Mehrfachvererbung
Mehrfache Vererbung des Status: Fähigkeit, Felder von mehreren Klassen zu erben
Wenn Mehrfachvererbung zulässig ist und Wenn Sie ein Objekt durch Instanziieren dieser Klasse erstellen, erbt dieses Objekt Felder von allen Oberklassen der Klasse. Es wird zwei Probleme verursachen.
Mehrfachvererbung der Implementierung: Möglichkeit, Methodendefinitionen von mehreren Klassen zu erben
Probleme mit diesem Ansatz: Namenskonflikte und Mehrdeutigkeiten . Wenn eine Unterklasse und eine Oberklasse denselben Methodennamen (und dieselbe Signatur) enthalten, kann der Compiler nicht bestimmen, welche Version aufgerufen werden soll.
Java unterstützt diese Art der Mehrfachvererbung jedoch mit Standardmethoden , die seit der Veröffentlichung von Java 8 eingeführt wurden. Der Java-Compiler bietet einige Regeln, um zu bestimmen, welche Standardmethode eine bestimmte Klasse verwendet.
Weitere Informationen zur Lösung des Diamantproblems finden Sie im folgenden SE-Beitrag:
Was sind die Unterschiede zwischen abstrakten Klassen und Schnittstellen in Java 8?
Mehrfachvererbung des Typs: Fähigkeit einer Klasse, mehr als eine Schnittstelle zu implementieren.
Da die Schnittstelle keine veränderlichen Felder enthält, müssen Sie sich hier keine Gedanken über Probleme machen, die sich aus der Mehrfachvererbung des Status ergeben.
quelle
Es wird gesagt, dass der Objektstatus in Bezug auf die darin enthaltenen Felder referenziert wird und es mehrdeutig werden würde, wenn zu viele Klassen geerbt würden. Hier ist der Link
http://docs.oracle.com/javase/tutorial/java/IandI/multipleinheritance.html
quelle
Java unterstützt die Mehrfachvererbung nur über Schnittstellen. Eine Klasse kann eine beliebige Anzahl von Schnittstellen implementieren, jedoch nur eine Klasse erweitern.
Mehrfachvererbung wird nicht unterstützt, da dies zu einem tödlichen Diamantproblem führt. Es kann jedoch gelöst werden, führt jedoch zu einem komplexen System, sodass die Java-Gründer die Mehrfachvererbung verworfen haben.
In einem Whitepaper mit dem Titel "Java: ein Überblick" von James Gosling im Februar 1995 ( Link ) wird eine Vorstellung davon gegeben, warum Mehrfachvererbung in Java nicht unterstützt wird.
Laut Gosling:
quelle
Aus dem gleichen Grund erlaubt C # keine Mehrfachvererbung, aber Sie können mehrere Schnittstellen implementieren.
Die Lehre aus C ++ mit Mehrfachvererbung war, dass es zu mehr Problemen führte, als es wert war.
Eine Schnittstelle ist ein Vertrag über Dinge, die Ihre Klasse implementieren muss. Sie erhalten keine Funktionalität von der Schnittstelle. Durch Vererbung können Sie die Funktionalität einer übergeordneten Klasse erben (und bei Mehrfachvererbung kann dies äußerst verwirrend sein).
Wenn Sie mehrere Schnittstellen zulassen, können Sie Entwurfsmuster (wie den Adapter) verwenden, um dieselben Arten von Problemen zu lösen, die Sie mit Mehrfachvererbung lösen können, jedoch auf eine viel zuverlässigere und vorhersehbarere Weise.
quelle
D1
undD2
beide vererbenB
, und jeder überschreibt eine Funktionf
, und wennobj
eine Instanz eines Typs ist ,S
die erbt von beidenD1
undD2
doch überschreibt nichtf
, dann einen Verweis GießenS
zuD1
sollte etwas , dessen Ausbeutef
Anwendungen dieD1
Überschreibung und dem GießenB
sollte nicht ändere das. Ebenso Gießen einen VerweisS
aufD2
sollte etwas , dessen Ausbeutef
Anwendungen dieD2
Überschreibung und GießenB
sollte daran nichts ändern. Wenn eine Sprache dasDa dieses Thema nicht eng ist, werde ich diese Antwort veröffentlichen. Ich hoffe, dies hilft jemandem zu verstehen, warum Java keine Mehrfachvererbung zulässt.
Betrachten Sie die folgende Klasse:
In diesem Fall erweitert die Klasse Abc nichts richtig? Diese implizite Klasse ist nicht so schnell und erweitert die Klasse Object, die Basisklasse, mit der alles in Java funktioniert. Alles ist ein Objekt.
Wenn Sie versuchen , die Klasse zu verwenden oben sehen Sie , dass Ihre IDE können Sie Methoden verwenden , wie:
equals(Object o)
,toString()
, etc, aber du hast nicht die Methoden erklären, kamen sie von der BasisklasseObject
Du könntest es versuchen:
Dies ist in Ordnung, da Ihre Klasse nicht implizit erweitert wird,
Object
sondern erweitert wird,String
weil Sie es gesagt haben. Betrachten Sie die folgende Änderung:Jetzt gibt Ihre Klasse immer "Hallo" zurück, wenn Sie toString () aufrufen.
Stellen Sie sich nun folgende Klasse vor:
Wieder Klasse
Flyer
Objekt implizit erstreckt , die das Verfahren hattoString()
, wird jede Klasse diese Methode haben , da sie alle sichObject
indirekt, also, wenn Sie rufentoString()
ausBird
, dietoString()
Java verwenden haben würde? VonAbc
oderFlyer
? Dies geschieht bei jeder Klasse, die versucht, zwei oder mehr Klassen zu erweitern. Um diese Art von "Methodenkollision" zu vermeiden, haben sie die Idee der Schnittstelle erstellt . Grundsätzlich könnte man sie als abstrakte Klasse betrachten, die Object nicht indirekt erweitert . Da sie abstrakt sind, müssen sie von einer Klasse implementiert werden, die ein Objekt ist (Sie können eine Schnittstelle nicht alleine instanziieren, sie muss von einer Klasse implementiert werden), damit alles weiterhin einwandfrei funktioniert.Um Klassen von Schnittstellen zu unterscheiden, wurde das Schlüsselwort implement nur für Schnittstellen reserviert.
Sie können jede beliebige Schnittstelle in derselben Klasse implementieren, da sie standardmäßig nichts erweitert (Sie können jedoch eine Schnittstelle erstellen, die eine andere Schnittstelle erweitert, aber auch die "Vater" -Schnittstelle würde Object nicht erweitern), also ist eine Schnittstelle Nur eine Schnittstelle, und sie leiden nicht unter " Methodensignaturspaltungen ". Wenn dies der Fall ist , gibt der Compiler eine Warnung an Sie aus und Sie müssen nur die Methodensignatur ändern, um sie zu beheben (Signatur = Methodenname + Parameter + Rückgabetyp). .
quelle
Weil eine Schnittstelle nur ein Vertrag ist. Und eine Klasse ist eigentlich ein Container für Daten.
quelle
Zum Beispiel zwei Klassen A, B mit derselben Methode m1 (). Und Klasse C erweitert sowohl A als auch B.
Jetzt sucht Klasse C nach der Definition von m1. Zuerst wird in der Klasse gesucht, wenn es nicht gefunden wurde, dann wird es in der Elternklasse überprüft. Sowohl A als auch B haben die Definition. Hier tritt also Mehrdeutigkeit auf, welche Definition gewählt werden soll. JAVA UNTERSTÜTZT also NICHT MEHRFACHE ERBUNG.
quelle
Java unterstützt aus zwei Gründen keine Mehrfachvererbung:
Object
Klasse. Wenn es von mehr als einer Superklasse erbt, erhält die Unterklasse die Mehrdeutigkeit, die Eigenschaft der Objektklasse zu erwerben.super()
auf, um den Konstruktor der Supper-Klasse aufzurufen. Wenn die Klasse mehr als eine Superklasse hat, wird sie verwirrt.Wenn sich eine Klasse von mehr als einer Superklasse erstreckt, erhalten wir einen Fehler bei der Kompilierung.
quelle
Nehmen wir zum Beispiel den Fall, dass Klasse A eine getSomething-Methode und Klasse B eine getSomething-Methode hat und Klasse C A und B erweitert. Was würde passieren, wenn jemand C.getSomething nennt? Es gibt keine Möglichkeit zu bestimmen, welche Methode aufgerufen werden soll.
Schnittstellen geben im Grunde nur an, welche Methoden eine implementierende Klasse enthalten muss. Eine Klasse, die mehrere Schnittstellen implementiert, bedeutet lediglich, dass die Klasse die Methoden aller dieser Schnittstellen implementieren muss. Whci würde zu keinen Problemen führen, wie oben beschrieben.
quelle
Stellen Sie sich ein Szenario vor, in dem Test1, Test2 und Test3 drei Klassen sind. Die Klasse Test3 erbt die Klassen Test2 und Test1. Wenn die Klassen Test1 und Test2 dieselbe Methode haben und Sie sie vom untergeordneten Klassenobjekt aufrufen, besteht eine Mehrdeutigkeit beim Aufrufen der Methode der Klasse Test1 oder Test2, es gibt jedoch keine solche Mehrdeutigkeit für die Schnittstelle, da in der Schnittstelle keine Implementierung vorhanden ist.
quelle
Java unterstützt aufgrund von Mehrdeutigkeitsproblemen keine Mehrfachvererbung, Mehrweg- und Hybridvererbung:
Mehrfachvererbung
quelle
Auf einfache Weise, die wir alle kennen, können wir eine Klasse erben (erweitern), aber wir können so viele Schnittstellen implementieren. Das liegt daran, dass wir in Schnittstellen keine Implementierung geben, sondern nur die Funktionalität. nehmen an, wenn Java kann so viele Klassen erweitert und die haben gleiche Methoden .. in diesem Punkt , wenn wir Superklasse aufzurufen Methode in der Unterklasse , welche Methode annehmen laufen versuchen ??, Compiler verwirren lassen Beispiel: - Versuchen Sie, um mehr erstreckt aber in Schnittstellen Diese Methoden haben keine Körper, die wir in der Unterklasse implementieren sollten. Versuchen Sie, mehrere Implementierungen durchzuführen, damit Sie sich keine Sorgen machen müssen.
quelle
* Dies ist eine einfache Antwort, da ich ein Anfänger in Java bin *
Bedenken Sie, dass es drei Klassen gibt
X
,Y
undZ
.Wir erben also wie
X extends Y, Z
Und beideY
undZ
haben eine Methodealphabet()
mit demselben Rückgabetyp und denselben Argumenten. Diese Methodealphabet()
inY
sagt, dass das erste Alphabet angezeigt werden soll, und das Methodenalphabet inZ
sagt, dass das letzte Alphabet angezeigt werden soll . Hier kommt also Mehrdeutigkeit, wenn vonalphabet()
aufgerufen wirdX
. Ob es heißt, erstes oder letztes Alphabet anzuzeigen ??? Java unterstützt also keine Mehrfachvererbung. Bei Schnittstellen betrachtenY
undZ
als Schnittstellen. Beide enthalten also die Deklaration der Methode,alphabet()
aber nicht die Definition. Es wird nicht angegeben, ob das erste oder das letzte Alphabet oder etwas anderes angezeigt werden soll, sondern nur eine Methode deklariertalphabet()
. Es gibt also keinen Grund, die Mehrdeutigkeit zu erhöhen. Wir können die Methode mit allem definieren, was wir innerhalb der Klasse wollenX
.Kurz gesagt, in Interfaces erfolgt die Definition nach der Implementierung, also keine Verwirrung.
quelle