Java erlaubt keine Mehrfachvererbung, aber die Implementierung mehrerer Schnittstellen. Warum?
Java erlaubt keine Mehrfachvererbung, aber die Implementierung mehrerer Schnittstellen. Warum?
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.
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.
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."
public class MyGodClass extends AppDomainObject, HttpServlet, MouseAdapter,
AbstractTableModel, AbstractListModel, AbstractList, AbstractMap, ...
Die Antwort auf diese Frage liegt in der internen Arbeitsweise des Java-Compilers (Konstruktorverkettung). Wenn wir die interne Arbeitsweise des Java-Compilers sehen:
public class Bank {
public void printBankBalance(){
System.out.println("10k");
}
}
class SBI extends Bank{
public void printBankBalance(){
System.out.println("20k");
}
}
Nach dem Kompilieren sieht dies so aus:
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");
}
}
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 wird 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");
}
}
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 neue static
Methode verweisen wir bitte auf die Standardeinstellung in der Schnittstelle .
Hoffe, dies wird Ihre Frage lösen. Vielen Dank.
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.
ToyotaCar
und HybridCar
beide abgeleitet von Car
und überschrieben Car.Drive
, und wennPriusCar
beide geerbt , aber nicht überschrieben werdenDrive
, hat das System keine Möglichkeit zu identifizieren, was die virtuelle Car.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 zwischen ToyotaCar::Drive
und 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, UseCar
zuerst an entweder HybridCar
oder 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.
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.
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.
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
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."
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.
D1
und D2
beide vererben B
, und jeder überschreibt eine Funktion f
, und wenn obj
eine Instanz eines Typs ist , S
die erbt von beiden D1
und D2
doch überschreibt nicht f
, dann einen Verweis Gießen S
zu D1
sollte etwas , dessen Ausbeute f
Anwendungen die D1
Überschreibung und dem Gießen B
sollte nicht ändere das. Ebenso Gießen einen Verweis S
auf D2
sollte etwas , dessen Ausbeute f
Anwendungen die D2
Überschreibung und Gießen B
sollte daran nichts ändern. Wenn eine Sprache das
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:
public class Abc{
public void 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
Du könntest es versuchen:
public class Abc extends String{
public void doSomething(){
}
}
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:
public class Abc{
public void doSomething(){
}
@Override
public String toString(){
return "hello";
}
}
Jetzt gibt Ihre Klasse immer "Hallo" zurück, wenn Sie toString () aufrufen.
Stellen Sie sich nun folgende Klasse vor:
public class Flyer{
public void makeFly(){
}
}
public class Bird extends Abc, Flyer{
public void doAnotherThing(){
}
}
Wieder Klasse Flyer
Objekt implizit erstreckt , die das Verfahren hat toString()
, wird jede Klasse diese Methode haben , da sie alle sich Object
indirekt, also, wenn Sie rufen toString()
aus Bird
, die toString()
Java verwenden haben würde? Von Abc
oder 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). .
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
}
Weil eine Schnittstelle nur ein Vertrag ist. Und eine Klasse ist eigentlich ein Container für Daten.
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.
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.
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.
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:
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.
Referenzlink: https://plus.google.com/u/0/communities/102217496457095083679
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.
* Dies ist eine einfache Antwort, da ich ein Anfänger in Java bin *
Bedenken Sie, dass es drei Klassen gibt X
, Y
und Z
.
Wir erben also wie X extends Y, Z
Und beide Y
und Z
haben eine Methode alphabet()
mit demselben Rückgabetyp und denselben Argumenten. Diese Methode alphabet()
in Y
sagt, dass das erste Alphabet angezeigt werden soll, und das Methodenalphabet in Z
sagt, 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 Y
und Z
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 wollen X
.
Kurz gesagt, in Interfaces erfolgt die Definition nach der Implementierung, also keine Verwirrung.