Nun, ich wollte fragen, was der Unterschied ist, aber es wurde schon beantwortet. Aber jetzt frage ich, warum haben sie diese Unterschiede gemacht? (Ich spreche hier über Java, ich weiß nicht, ob das auch für andere Sprachen gilt)
Die beiden Dinge scheinen sich sehr ähnlich zu sein. Abstrakte Klassen können einen Methodenkörper definieren, während Interfaces dies nicht können, aber mehrere Interfaces vererbt werden können. Warum also haben sie nicht (durch "sie" meine ich Sun, als sie Java geschrieben haben) eine Sache gemacht, wo man eine Methode body schreiben kann und diese Art kann mehr als einmal von einer Klasse geerbt werden / p>
Gibt es einen Vorteil darin, dass ich nicht in der Lage bin, einen Methodenkörper zu schreiben oder mehrere Male zu verlängern, die ich nicht sehe?
Da es zulässt, dass Klassen mehrere Implementierungen für dieselbe Methodensignatur erben, führt das zu der offensichtlichen Frage, welche zur Laufzeit verwendet werden sollte.
Java vermeidet dies, indem es die Mehrfachvererbung nur für Schnittstellen unterstützt. Die in jeder Schnittstelle deklarierten Signaturen können viel einfacher kombiniert werden (Java verwendet grundsätzlich die Vereinigung aller Methoden)
Die mehrfache Vererbung in C ++ führt zu semantischen Ambiguitäten wie Diamantvererbungsproblem . MI ist ziemlich mächtig, hat aber komplexe Konsequenzen.
Durch die Spezialisierung von Schnittstellen wird auch die Sichtbarkeit des Konzepts erhöht, um die Komplexität von Informationen zu verbergen und zu reduzieren. In C ++ ist das Definieren reiner abstrakter Grundlagen ein Zeichen für einen ausgereiften Programmierer. In Java begegnen Sie ihnen zu einem viel früheren Zeitpunkt in der Entwicklung eines Programmierers.
Mehrfache Vererbung ist in einer Sprache (Compiler wirklich) schwieriger zu implementieren, da es zu bestimmten Problemen führen kann. Diese Probleme wurden bereits zuvor besprochen: Was ist das genaue Problem mit der Mehrfachvererbung? .
Ich habe immer angenommen, dass dies ein Kompromiss in Java ist. Schnittstellen ermöglichen es einer Klasse, mehrere Verträge ohne Mehrfachvererbung zu erfüllen.
Betrachten Sie dieses Beispiel:
%Vor%Die abstrakte Klasse kann Ihnen dabei helfen, über solide Basismethoden zu verfügen, die überschrieben werden können oder nicht, aber in diesen Methoden verwendet sie abstrakte Methoden, um Ihnen die Möglichkeit zu geben, Ihre spezifische Sache zu tun. In meinem Beispiel haben verschiedene Motoren unterschiedliche Implementierungen, wie sie den Strom einschalten, etwas Kraftstoff für die Zündung streuen und die Zündung machen, jedoch bleibt die Startsequenz des Motors immer gleich.
Dieses Muster wird "Form Template Method" genannt und ist ehrlich gesagt die einzig sinnvolle Verwendung von abstrakten Klassen in Java für mich.
Sie zu einer Sache zu machen, ist der Weg, den die Scala-Leute mit Traits eingeschlagen haben, eine Schnittstelle, die Methoden haben und mehrfache Vererbung unterstützen kann.
Ich denke, Schnittstellen sind für mich insofern sauber, als sie nur Anforderungen spezifizieren (Design by Contract), während abstrakte Klassen ein gemeinsames Verhalten (Implementierung) definieren, also ein anderes Werkzeug für einen anderen Job? Schnittstellen erlauben wahrscheinlich auch eine effizientere Code-Generierung während der Kompilierzeit?
Der andere Ansatz, den Sie beschreiben, ist der von C ++ verwendete Ansatz (zB Mixins). Die Probleme im Zusammenhang mit einer solchen "Mehrfachvererbung" sind ziemlich komplex und haben in C ++ mehrere Kritikpunkte.
Vererbung bedeutet, dass Sie die Natur (Bedeutung) und Verantwortlichkeit (Verhalten) der Elternklasse erben, während die Schnittstellenimplementierung bedeutet, dass Sie einen Vertrag (z. B. Serializable) erfüllen kann nichts mit der Kernnatur oder Verantwortung der Klasse zu tun haben.
Mit der abstrakten Klasse können Sie eine Natur definieren, die Sie generisch und nicht direkt instanziierbar haben möchten, da sie spezialisiert sein muss. Sie wissen, wie Sie einige Aufgaben auf hoher Ebene ausführen (z. B. eine Entscheidung gemäß einigen Parametern treffen), aber Sie kennen die Details für einige untergeordnete Aktionen nicht (z. B. einige Zwischenparameter berechnen), da dies von Implementierungsentscheidungen abhängt. Eine Alternative zur Lösung dieses Problems ist das Strategie-Design-Pattern . Es ist flexibler, erlaubt Laufzeit-Strategie-Wechsel und Null-Verhalten, ist aber komplexer (und Laufzeit-Switching ist nicht immer notwendig). Darüber hinaus könnten Sie einige Bedeutung & amp; Tipp-Möglichkeiten (Polymorphie und Typ-Überprüfung wird etwas schwieriger, weil die Strategie eine Komponente ist, nicht das Objekt selbst).
Abstrakte Klasse = ist-a, Strategie = hat-a
Edit: wie bei der Mehrfachvererbung, siehe Pontus Gagge's Antwort.
Tags und Links java multiple-inheritance interface abstract-class