In einem meiner Interviews wurde ich gebeten, den Unterschied zwischen einer Interface- und einer Abstract-Klasse zu erklären .
Hier ist meine Antwort:
Methoden einer Java-Schnittstelle sind implizit abstrakt und können nicht implementiert werden. Eine abstrakte Java-Klasse kann Instanzmethoden haben, die ein Standardverhalten implementieren.
In einer Java-Schnittstelle deklarierte Variablen sind standardmäßig final. Eine abstrakte Klasse kann nicht endgültige Variablen enthalten.
Mitglieder einer Java-Schnittstelle sind standardmäßig öffentlich. Eine abstrakte Java-Klasse kann die üblichen Varianten von Klassenmitgliedern wie privat, geschützt usw. haben.
Eine Java-Schnittstelle sollte mit dem Schlüsselwort "implementiert" implementiert werden. Eine abstrakte Java-Klasse sollte mit dem Schlüsselwort "erweitert" erweitert werden.
Eine Schnittstelle kann nur eine andere Java-Schnittstelle erweitern, eine abstrakte Klasse kann eine andere Java-Klasse erweitern und mehrere Java-Schnittstellen implementieren.
Eine Java-Klasse kann mehrere Schnittstellen implementieren, aber nur eine abstrakte Klasse erweitern.
Der Interviewer war jedoch nicht zufrieden und sagte mir, dass diese Beschreibung " Buchwissen " darstelle.
Er bat mich um eine praktischere Antwort und erklärte anhand praktischer Beispiele , wann ich eine abstrakte Klasse über eine Schnittstelle wählen würde .
Was habe ich falsch gemacht?
quelle
Antworten:
Ich werde Ihnen zuerst ein Beispiel geben:
Angenommen, Ihre Anwendung enthält 3 Datenbanken. Dann muss jede Implementierung für diese Datenbank die beiden oben genannten Methoden definieren:
Aber was ist, wenn
encryptPassword()
es nicht datenbankabhängig ist und für jede Klasse gleich ist? Dann wäre das oben Genannte kein guter Ansatz.Betrachten Sie stattdessen diesen Ansatz:
Jetzt müssen wir in jeder untergeordneten Klasse nur noch eine Methode implementieren - die datenbankabhängige Methode.
quelle
Nichts ist perfekt auf dieser Welt. Sie haben vielleicht eher einen praktischen Ansatz erwartet.
Nach Ihrer Erklärung können Sie diese Zeilen jedoch mit einem etwas anderen Ansatz hinzufügen.
Schnittstellen sind Regeln (Regeln, weil Sie ihnen eine Implementierung geben müssen, die Sie nicht ignorieren oder vermeiden können, damit sie wie Regeln auferlegt werden), die als gemeinsames Verständnisdokument für verschiedene Teams in der Softwareentwicklung dienen.
Schnittstellen geben die Idee, was zu tun ist, aber nicht, wie es getan werden soll. Die Implementierung hängt also vollständig vom Entwickler ab, indem die angegebenen Regeln befolgt werden (dh die Signatur der Methoden).
Abstrakte Klassen können abstrakte Deklarationen, konkrete Implementierungen oder beides enthalten.
Abstrakte Deklarationen sind wie Regeln, die befolgt werden müssen, und konkrete Implementierungen sind wie Richtlinien (Sie können sie so verwenden, wie sie sind, oder Sie können sie ignorieren, indem Sie sie überschreiben und Ihre eigene Implementierung geben).
Darüber hinaus werden als Schnittstellendeklarationen als Regeln bereitgestellt, welche Methoden mit derselben Signatur das Verhalten in verschiedenen Kontexten ändern können, um sie in verschiedenen Kontexten entsprechend zu implementieren.
Bearbeiten: Java 8 erleichtert das Definieren von Standard- und statischen Methoden in der Schnittstelle.
Wenn eine Klasse SomeInterface implementiert, ist es nicht zwingend erforderlich, die Implementierung für Standardschnittstellenmethoden bereitzustellen.
Wenn wir eine andere Schnittstelle mit folgenden Methoden haben:
Java erlaubt nicht die Erweiterung mehrerer Klassen, da dies zu einem „Diamond-Problem“ führt, bei dem der Compiler nicht entscheiden kann, welche Superklassenmethode verwendet werden soll. Mit den Standardmethoden tritt das Diamantproblem auch für Schnittstellen auf. Denn wenn eine Klasse beides implementiert
und implementiert nicht die übliche Standardmethode, kann der Compiler nicht entscheiden, welche er wählen soll. Um dieses Problem zu vermeiden, müssen in Java 8 gemeinsame Standardmethoden für verschiedene Schnittstellen implementiert werden. Wenn eine Klasse beide oben genannten Schnittstellen implementiert, muss sie die Implementierung für die defaultMethod () -Methode bereitstellen, da sonst der Compiler einen Fehler bei der Kompilierungszeit auslöst.
quelle
Sie haben die praktischen Unterschiede in Verwendung und Implementierung gut zusammengefasst, aber nichts über den Unterschied in der Bedeutung gesagt.
Eine Schnittstelle beschreibt das Verhalten einer implementierenden Klasse. Die implementierende Klasse stellt sicher, dass diese Methoden verwendet werden können. Es ist im Grunde ein Vertrag oder ein Versprechen, das die Klasse machen muss.
Eine abstrakte Klasse ist eine Basis für verschiedene Unterklassen, die ein gemeinsames Verhalten aufweisen, das nicht wiederholt erstellt werden muss. Unterklassen müssen das Verhalten vervollständigen und die Option haben, vordefiniertes Verhalten zu überschreiben (sofern es nicht als
final
oder definiert istprivate
).Sie finden gute Beispiele in dem
java.util
Paket, das Schnittstellen wieList
und abstrakte Klassen enthält,AbstractList
die die Schnittstelle bereits implementieren. Die offizielle Dokumentation beschreibtAbstractList
Folgendes:quelle
abstract
Schlüsselwörtern. Wenn ein Compiler dies sieht, weiß er, dass die folgenden Informationen unvollständig sind und implementiert werden müssen . Schnittstellen sind immer unvollständig, aber abstrakte Klassen sind abstrakt, weil sieincomplete (abstract)
Methoden haben mussten.Eine Schnittstelle besteht aus Singleton-Variablen (public static final) und öffentlichen abstrakten Methoden. Normalerweise bevorzugen wir die Verwendung einer Schnittstelle in Echtzeit, wenn wir wissen, was zu tun ist, aber nicht wissen, wie es geht .
Dieses Konzept kann anhand eines Beispiels besser verstanden werden:
Betrachten Sie eine Zahlungsklasse. Die Zahlung kann auf viele Arten erfolgen, z. B. über PayPal, Kreditkarte usw. Daher verwenden wir normalerweise die Zahlung als Schnittstelle, die eine
makePayment()
Methode enthält , und CreditCard und PayPal sind die beiden Implementierungsklassen.Im obigen Beispiel sind CreditCard und PayPal zwei Implementierungsklassen / -strategien. Eine Schnittstelle ermöglicht uns auch das Konzept der Mehrfachvererbung in Java, das von einer abstrakten Klasse nicht ausgeführt werden kann.
Wir wählen eine abstrakte Klasse, wenn es einige Funktionen gibt, für die wir wissen, was zu tun ist, und andere Funktionen, die wir ausführen können .
Betrachten Sie das folgende Beispiel:
Wenn wir einer bestimmten abstrakten Klasse in Zukunft Methoden (konkret / abstrakt) hinzufügen, muss die Implementierungsklasse ihren Code nicht ändern. Wenn wir jedoch in Zukunft Methoden in einer Schnittstelle hinzufügen, müssen wir allen Klassen, die diese Schnittstelle implementiert haben, Implementierungen hinzufügen, da sonst Fehler bei der Kompilierung auftreten.
Es gibt andere Unterschiede, aber dies sind wichtige, die möglicherweise von Ihrem Interviewer erwartet wurden. Hoffentlich war das hilfreich.
quelle
interface
und wählenabstract class
.Unterschied zwischen Abstact-Klasse und Schnittstelle
Standardmethoden der Schnittstelle in Java 8
Statische Methode der Java-Schnittstelle
Java-Funktionsschnittstellen
Abstrakte Klassen versus Schnittstellen in Java 8
Konzeptioneller Unterschied:
Abstrakte Klassen gelten für skelettartige (dh teilweise) Implementierungen von Schnittstellen, sollten jedoch ohne eine passende Schnittstelle nicht existieren.
Können abstrakte Klassen dies auch beseitigen, wenn abstrakte Klassen effektiv auf eine geringe Sichtbarkeit reduziert werden, Skelettimplementierungen von Schnittstellen? Entschlossen: Nein! Das Implementieren von Schnittstellen erfordert fast immer einige oder alle dieser Tools zum Erstellen von Klassen, die Standardmethoden fehlen. Und wenn einige Schnittstellen dies nicht tun, handelt es sich eindeutig um einen Sonderfall, der Sie nicht in die Irre führen sollte.
Standardmethoden der Schnittstelle in Java 8
Java 8 führt die neue Funktion " Standardmethode " oder (Verteidigungsmethoden) ein, mit der Entwickler den Schnittstellen neue Methoden hinzufügen können, ohne die vorhandene Implementierung dieser Schnittstelle zu beschädigen. Es bietet Flexibilität, um die Implementierung der Schnittstellendefinition zu ermöglichen, die standardmäßig verwendet wird, wenn eine konkrete Klasse keine Implementierung für diese Methode bereitstellt.
Betrachten wir ein kleines Beispiel, um zu verstehen, wie es funktioniert:
Die folgende Klasse wird erfolgreich in Java JDK 8 kompiliert:
Wenn Sie eine Instanz von OldInterfaceImpl erstellen:
Standardmethode:
Standardmethoden können einer Schnittstelle bereitgestellt werden, ohne die Implementierung von Klassen zu beeinflussen, da sie eine Implementierung enthält. Wenn jede hinzugefügte Methode in einer mit der Implementierung definierten Schnittstelle keine implementierende Klasse betrifft. Eine implementierende Klasse kann die von der Schnittstelle bereitgestellte Standardimplementierung überschreiben.
Wenn wir eine Schnittstelle erweitern, die eine Standardmethode enthält, können wir Folgendes ausführen:
Für jede Methode wurde ein Kompilierungsfehler mit der Standardmethode behoben
Für Java 8 wurden die JDK-Sammlungen erweitert und die forEach-Methode zur gesamten Sammlung hinzugefügt (die in Verbindung mit Lambdas funktioniert). Auf herkömmliche Weise sieht der Code wie folgt aus:
Da dies zu jeder implementierenden Klasse mit Kompilierungsfehlern führt, wird eine Standardmethode mit einer erforderlichen Implementierung hinzugefügt, damit die vorhandene Implementierung nicht geändert wird.
Die iterierbare Schnittstelle mit der Standardmethode ist unten aufgeführt.
Der gleiche Mechanismus wurde verwendet, um Stream in der JDK-Schnittstelle hinzuzufügen, ohne die implementierenden Klassen zu beschädigen.
Probleme mit der Standardmethode und Mehrdeutigkeit bei Mehrfachvererbung
Da die Java-Klasse mehrere Schnittstellen implementieren kann und jede Schnittstelle eine Standardmethode mit derselben Methodensignatur definieren kann, können die geerbten Methoden miteinander in Konflikt stehen.
Betrachten Sie das folgende Beispiel:
Der obige Code kann mit dem folgenden Fehler nicht kompiliert werden:
Um diese Klasse zu reparieren, müssen wir die Standardmethodenimplementierung bereitstellen:
Wenn wir die Standardimplementierung aufrufen möchten, die von einer der Super-Schnittstellen bereitgestellt wird, und nicht von unserer eigenen Implementierung, können wir dies wie folgt tun:
Wir können im Rahmen unserer neuen Methode jede Standardimplementierung oder beides auswählen.
Wichtige Punkte zu den Standardmethoden der Java-Schnittstelle:
Ressourcenlink:
Statische Methode der Java-Schnittstelle
Statische Methode der Java-Schnittstelle, Codebeispiel, statische Methode vs. Standardmethode
Die statische Methode der Java-Schnittstelle ähnelt der Standardmethode, außer dass wir sie in den Implementierungsklassen nicht überschreiben können. Diese Funktion hilft uns dabei, unerwünschte Ergebnisse bei schlechter Implementierung in Implementierungsklassen zu vermeiden. Lassen Sie uns dies anhand eines einfachen Beispiels untersuchen.
Lassen Sie uns nun eine Implementierungsklasse sehen, die eine isNull () -Methode mit schlechter Implementierung hat.
Beachten Sie, dass isNull (String str) eine einfache Klassenmethode ist und die Schnittstellenmethode nicht überschreibt. Wenn wir beispielsweise der isNull () -Methode eine @ Override-Annotation hinzufügen, führt dies zu einem Compilerfehler.
Wenn wir nun die Anwendung ausführen, erhalten wir folgende Ausgabe.
Wenn wir die Schnittstellenmethode von statisch auf Standard setzen, erhalten wir folgende Ausgabe.
Die statische Methode der Java-Schnittstelle ist nur für Schnittstellenmethoden sichtbar. Wenn wir die Methode isNull () aus der MyDataImpl-Klasse entfernen, können wir sie nicht für das MyDataImpl-Objekt verwenden. Wie bei anderen statischen Methoden können wir jedoch statische Schnittstellenmethoden unter Verwendung des Klassennamens verwenden. Eine gültige Anweisung lautet beispielsweise:
Wichtige Punkte zur statischen Methode der Java-Schnittstelle:
Java-Funktionsschnittstellen
Bevor ich den Beitrag abschließe, möchte ich eine kurze Einführung in funktionale Schnittstellen geben. Eine Schnittstelle mit genau einer abstrakten Methode wird als funktionale Schnittstelle bezeichnet.
Eine neue Anmerkung
@FunctionalInterface
wurde eingeführt, um eine Schnittstelle als funktionale Schnittstelle zu markieren.@FunctionalInterface
Annotation ist eine Möglichkeit, das versehentliche Hinzufügen abstrakter Methoden zu den Funktionsschnittstellen zu vermeiden. Es ist optional, aber eine gute Praxis, es zu verwenden.Funktionale Schnittstellen werden von Java 8 lange erwartet und sind sehr gefragt, da sie es uns ermöglichen, Lambda-Ausdrücke zu verwenden, um sie zu instanziieren. Ein neues Paket java.util.function mit einer Reihe von Funktionsschnittstellen wurde hinzugefügt, um Zieltypen für Lambda-Ausdrücke und Methodenreferenzen bereitzustellen. Wir werden uns in zukünftigen Beiträgen mit funktionalen Schnittstellen und Lambda-Ausdrücken befassen.
Ressourcenstandort:
quelle
Alle Ihre Anweisungen sind gültig, mit Ausnahme Ihrer ersten Anweisung (nach der Java 8-Version):
Aus der Dokumentation Seite :
Standardmethoden:
Eine Schnittstelle kann Standardmethoden haben , unterscheidet sich jedoch von abstrakten Methoden in abstrakten Klassen.
Wenn Sie eine Schnittstelle erweitern, die eine Standardmethode enthält, können Sie Folgendes tun:
abstract
.Statische Methoden:
Zusätzlich zu den Standardmethoden können Sie statische Methoden in Schnittstellen definieren. (Eine statische Methode ist eine Methode, die der Klasse zugeordnet ist, in der sie definiert ist, und nicht einem Objekt. Jede Instanz der Klasse teilt ihre statischen Methoden.)
Dies erleichtert Ihnen das Organisieren von Hilfsmethoden in Ihren Bibliotheken.
Beispielcode von der Dokumentationsseite über
interface
Habenstatic
unddefault
Methoden.Verwenden Sie die folgenden Richtlinien, um auszuwählen, ob eine Schnittstelle oder eine abstrakte Klasse verwendet werden soll.
Schnittstelle:
Abstrakte Klasse:
Teilen Sie den Code zwischen mehreren eng verwandten Klassen. Es stellt eine Beziehung her.
Gemeinsamen Status zwischen verwandten Klassen teilen (Status kann in konkreten Klassen geändert werden)
Zusammenhängende Posts:
Interface vs Abstract Class (allgemeines OO)
Implementiert vs erweitert: Wann verwenden? Was ist der Unterschied?
Wenn Sie diese Beispiele durchgehen, können Sie das verstehen
Nicht verwandte Klassen können Funktionen über die Schnittstelle haben, aber verwandte Klassen ändern das Verhalten durch Erweiterung von Basisklassen.
quelle
stateless
In-Schnittstelle ist ein schöner Hit. Die Schnittstelle kann keinen Zustand haben (die Schnittstelle kann Konstanten haben, aber sie sind endgültig / statisch und daher unveränderlich).Ihre Erklärung sieht anständig aus, aber könnte es so aussehen, als hätten Sie alles aus einem Lehrbuch gelesen? : - /
Was mich mehr stört ist, wie solide war Ihr Beispiel? Haben Sie sich die Mühe gemacht, fast alle Unterschiede zwischen Abstract und Interfaces zu berücksichtigen?
Persönlich würde ich diesen Link vorschlagen: http://mindprod.com/jgloss/interfacevsabstract.html#TABLE
für eine vollständige Liste der Unterschiede ..
Ich hoffe, es hilft Ihnen und allen anderen Lesern bei ihren zukünftigen Interviews
quelle
Viele Nachwuchsentwickler machen den Fehler, Schnittstellen, abstrakte und konkrete Klassen als geringfügige Abweichungen derselben zu betrachten, und wählen eine davon nur aus technischen Gründen: Benötige ich Mehrfachvererbung? Benötige ich einen Platz, um gängige Methoden anzuwenden? Muss ich mich mit etwas anderem als nur einer konkreten Klasse beschäftigen? Das ist falsch und in diesen Fragen verbirgt sich das Hauptproblem: "Ich" . Wenn Sie selbst Code schreiben, denken Sie selten an andere gegenwärtige oder zukünftige Entwickler, die an oder mit Ihrem Code arbeiten.
Schnittstellen und abstrakte Klassen haben, obwohl sie aus technischer Sicht offensichtlich ähnlich sind, völlig unterschiedliche Bedeutungen und Zwecke.
Zusammenfassung
Eine Schnittstelle definiert einen Vertrag , den eine Implementierung für Sie erfüllen wird .
Eine abstrakte Klasse bietet ein Standardverhalten, das Ihre Implementierung wiederverwenden kann.
Diese beiden Punkte oben sind das, wonach ich beim Interview suche, und sie sind kompakt genug. Lesen Sie weiter für weitere Details.
Alternative Zusammenfassung
Zum Beispiel
Anders ausgedrückt: Eine konkrete Klasse erledigt die eigentliche Arbeit auf ganz bestimmte Weise. Beispielsweise
ArrayList
verwendet a einen zusammenhängenden Speicherbereich, um eine Liste von Objekten auf kompakte Weise zu speichern, die schnellen Direktzugriff, Iteration und direkte Änderungen bietet, aber beim Einfügen, Löschen und gelegentlich sogar beim Hinzufügen schrecklich ist. in der Zwischenzeit aLinkedList
verwendet doppelt verknüpfte Knoten, um eine Liste von Objekten zu speichern, die stattdessen eine schnelle Iteration, direkte Änderungen und das Einfügen / Löschen / Hinzufügen bietet, aber bei wahlfreiem Zugriff schrecklich ist. Diese beiden Arten von Listen sind für verschiedene Anwendungsfälle optimiert, und es ist sehr wichtig, wie Sie sie verwenden werden. Wenn Sie versuchen, die Leistung aus einer Liste herauszuholen, mit der Sie stark interagieren, und wenn Sie die Art der Liste auswählen, sollten Sie sorgfältig auswählen, welche Sie instanziieren.Auf der anderen Seite ist es hochrangigen Benutzern einer Liste egal, wie sie tatsächlich implementiert wird, und sie sollten von diesen Details isoliert sein. Stellen wir uns vor, Java hat die
List
Schnittstelle nicht verfügbar gemacht , sondern nur eine konkreteList
Klasse, dieLinkedList
genau das ist, was gerade ist. Alle Java-Entwickler hätten ihren Code an die Implementierungsdetails angepasst: Vermeiden Sie Direktzugriff, fügen Sie einen Cache hinzu, um den Zugriff zu beschleunigen, oder implementierenArrayList
Sie ihn einfach selbst neu, obwohl er nicht mit allen anderen Codes kompatibel wäre, mit denen tatsächlich gearbeitet wirdList
. Das wäre schrecklich ... Aber stellen Sie sich jetzt vor, dass die Java-Master tatsächlich erkennen, dass eine verknüpfte Liste für die meisten tatsächlichen Anwendungsfälle schrecklich ist, und beschlossen, nur für ihre auf eine Array-Liste umzuschaltenList
Klasse verfügbar. Dies würde die Leistung jedes Java-Programms auf der Welt beeinträchtigen, und die Leute würden sich nicht darüber freuen. Der Hauptschuldige ist, dass Implementierungsdetails verfügbar waren, und die Entwickler gingen davon aus, dass diese Details ein dauerhafter Vertrag sind, auf den sie sich verlassen können. Aus diesem Grund ist es wichtig, Implementierungsdetails auszublenden und nur einen abstrakten Vertrag zu definieren. Dies ist der Zweck einer Schnittstelle: Definieren Sie, welche Art von Eingabe eine Methode akzeptiert und welche Art von Ausgabe erwartet wird, ohne alle Eingeweide aufzudecken, die Programmierer dazu verleiten würden, ihren Code so anzupassen, dass er den internen Details entspricht, die sich bei zukünftigen Updates ändern könnten .Eine abstrakte Klasse befindet sich in der Mitte zwischen Schnittstellen und konkreten Klassen. Es soll Implementierungen helfen, gemeinsamen oder langweiligen Code zu teilen. Zum Beispiel
AbstractCollection
bietet grundlegende Implementierungen fürisEmpty
basierend auf der Größe 0 ist,contains
als Iterierte und vergleichen,addAll
wie wiederholtadd
, und so weiter. Auf diese Weise können sich Implementierungen auf die entscheidenden Teile konzentrieren, die zwischen ihnen unterscheiden: das tatsächliche Speichern und Abrufen von Daten.Eine andere Perspektive: APIs versus SPIs
Schnittstellen sind Gateways mit geringer Kohäsion zwischen verschiedenen Teilen des Codes. Sie ermöglichen es Bibliotheken, zu existieren und sich weiterzuentwickeln, ohne jeden Bibliotheksbenutzer zu beschädigen, wenn sich intern etwas ändert. Es heißt Application Programming Interface - nicht Application Programming Klassen. In kleinerem Maßstab ermöglichen sie auch mehreren Entwicklern die erfolgreiche Zusammenarbeit bei großen Projekten, indem sie verschiedene Module durch gut dokumentierte Schnittstellen trennen.
Abstrakte Klassen sind hochkohäsive Helfer , die bei der Implementierung einer Schnittstelle verwendet werden können, vorausgesetzt, dass einige Implementierungsdetails vorhanden sind. Alternativ werden abstrakte Klassen zum Definieren von SPIs (Service Provider Interfaces) verwendet.
Der Unterschied zwischen einer API und einem SPI ist subtil, aber wichtig: Bei einer API liegt der Fokus darauf, wer sie verwendet , und bei einem SPI liegt der Fokus darauf, wer sie implementiert .
Das Hinzufügen von Methoden zu einer API ist einfach. Alle vorhandenen Benutzer der API werden weiterhin kompiliert. Das Hinzufügen von Methoden zu einem SPI ist schwierig, da jeder Dienstanbieter (konkrete Implementierung) die neuen Methoden implementieren muss. Wenn zum Definieren eines SPI Schnittstellen verwendet werden, muss ein Anbieter bei jeder Änderung des SPI-Vertrags eine neue Version veröffentlichen. Wenn stattdessen abstrakte Klassen verwendet werden, können neue Methoden entweder als vorhandene abstrakte Methoden oder als leere
throw not implemented exception
Stubs definiert werden, sodass zumindest eine ältere Version einer Service-Implementierung weiterhin kompiliert und ausgeführt werden kann.Ein Hinweis zu Java 8 und Standardmethoden
Obwohl Java 8 Standardmethoden für Schnittstellen eingeführt hat, die die Grenze zwischen Schnittstellen und abstrakten Klassen noch unschärfer machen, war dies nicht so, dass Implementierungen Code wiederverwenden können, sondern um das Ändern von Schnittstellen zu erleichtern, die sowohl als API als auch als SPI dienen (oder werden fälschlicherweise zum Definieren von SPIs anstelle von abstrakten Klassen verwendet).
"Buchwissen"
Die technischen Details, die in der Antwort des OP enthalten sind, werden als "Buchwissen" betrachtet, da dies normalerweise der Ansatz ist, der in der Schule und in den meisten Technologiebüchern über eine Sprache verwendet wird: Was ist eine Sache, nicht wie man sie in der Praxis verwendet, insbesondere in großen Anwendungen .
Hier ist eine Analogie: Angenommen, die Frage war:
Die technische Antwort klingt wie folgt:
Das ist alles wahr, aber es fehlen völlig die Punkte, dass es sich um zwei völlig verschiedene Dinge handelt, und beide können gleichzeitig für verschiedene Zwecke verwendet werden, und der Aspekt "es zu tun" ist nicht das Wichtigste bei beiden Optionen . Der Antwort fehlt die Perspektive, sie zeigt eine unreife Denkweise und präsentiert gleichzeitig wahre "Fakten".
quelle
Was ist mit folgendem Denken:
Wenn Sie also eine abstrakte Klasse Säugetiere, eine Unterklasse Mensch und eine Schnittstelle Fahren haben, können Sie sagen
Mein Vorschlag ist, dass der Buchwissenssatz anzeigt, dass er den semantischen Unterschied zwischen beiden hören wollte (wie andere hier bereits vorgeschlagen).
quelle
Eine Schnittstelle ist ein "Vertrag", bei dem die Klasse, die den Vertrag implementiert, verspricht, die Methoden zu implementieren. Ein Beispiel, bei dem ich anstelle einer Klasse eine Benutzeroberfläche schreiben musste, war, als ich ein Spiel von 2D auf 3D aktualisierte. Ich musste eine Schnittstelle erstellen, um Klassen zwischen der 2D- und der 3D-Version des Spiels zu teilen.
Dann kann ich die Methoden basierend auf der Umgebung implementieren und gleichzeitig diese Methoden von einem Objekt aus aufrufen, das nicht weiß, welche Version des Spiels geladen wird.
public class Adventure extends JFrame implements Playable
public class Dungeon3D extends SimpleApplication implements Playable
public class Main extends SimpleApplication implements AnimEventListener, ActionListener, Playable
Typischerweise kann in der Spielwelt die Welt eine abstrakte Klasse sein, die Methoden für das Spiel ausführt:
quelle
Abstrakte Klassen sind keine reine Abstraktion, da sie sowohl konkrete (implementierte) Methoden als auch nicht implementierte Methoden enthalten. Aber Schnittstellen sind reine Abstraktion, da es nur nicht implementierte Methoden gibt, keine konkreten Methoden.
Warum abstrakte Klassen?
Warum Schnittstellen?
quelle
Eine Schnittstelle ist wie eine Reihe von Genen, die öffentlich dokumentiert sind, um eine Wirkung zu erzielen: Ein DNA-Test zeigt mir, ob ich sie habe - und wenn ja, kann ich öffentlich bekannt machen, dass ich ein "Träger" bin "und ein Teil meines Verhaltens oder Zustands wird ihnen entsprechen. (Aber natürlich kann ich viele andere Gene haben, die Merkmale außerhalb dieses Bereichs liefern.)
Eine abstrakte Klasse ist wie die tote Vorfahrin einer gleichgeschlechtlichen Spezies (*): Sie kann nicht zum Leben erweckt werden, aber ein lebender (dh nicht abstrakter ) Nachkomme erbt alle ihre Gene.
(*) Um diese Metapher zu erweitern, nehmen wir an, dass alle Mitglieder der Spezies im gleichen Alter leben. Dies bedeutet, dass auch alle Vorfahren eines toten Vorfahren tot sein müssen - und ebenso müssen alle Nachkommen eines lebenden Vorfahren am Leben sein.
quelle
Ich mache Interviews für die Arbeit und würde auch auf Ihre Antwort ungünstig schauen (sorry, aber ich bin sehr ehrlich). Es hört sich so an, als hätten Sie über den Unterschied gelesen und eine Antwort überarbeitet, aber vielleicht haben Sie sie in der Praxis noch nie verwendet.
Eine gute Erklärung, warum Sie jedes verwenden würden, kann weitaus besser sein, als eine genaue Erklärung des Unterschieds zu haben. Die Arbeitgeber möchten letztendlich, dass die Programmierer Dinge tun, die sie nicht kennen, was in einem Interview schwer zu demonstrieren sein kann. Die Antwort, die Sie gegeben haben, wäre gut, wenn Sie sich für einen technischen oder dokumentationsbasierten Job bewerben würden, aber nicht für eine Entwicklerrolle.
Viel Glück mit Interviews in der Zukunft.
Meine Antwort auf diese Frage bezieht sich eher auf die Interviewtechnik als auf das von Ihnen bereitgestellte technische Material. Vielleicht darüber nachdenken, darüber zu lesen. https://workplace.stackexchange.com/ kann ein ausgezeichneter Ort für solche Dinge sein.
quelle
Sie wählen Schnittstelle in Java, um das Diamond-Problem bei Mehrfachvererbung zu vermeiden .
Wenn Sie möchten, dass alle Ihre Methoden von Ihrem Client implementiert werden, wählen Sie die Schnittstelle. Dies bedeutet, dass Sie die gesamte Anwendung abstrakt gestalten.
Sie wählen eine abstrakte Klasse, wenn Sie bereits wissen, was gemeinsam ist. Nehmen Sie zum Beispiel eine abstrakte Klasse
Car
. Auf höherer Ebene implementieren Sie die gängigen Automethoden wiecalculateRPM()
. Es ist eine übliche Methode, und Sie lassen den Kunden sein eigenes Verhalten wiecalculateMaxSpeed()
usw. implementieren . Wahrscheinlich hätten Sie dies anhand einiger Echtzeitbeispiele erklärt, auf die Sie in Ihrer täglichen Arbeit gestoßen sind.quelle
Eine Schnittstelle ist rein abstrakt. Wir haben keinen Implementierungscode in der Schnittstelle.
Die abstrakte Klasse enthält beide Methoden und ihre Implementierung.
Klicken Sie hier, um das Tutorial zu Schnittstellen und abstrakten Klassen anzusehen
quelle
Der Hauptunterschied, den ich beobachtet habe, war, dass die abstrakte Klasse uns ein allgemeines Verhalten bietet, das bereits implementiert ist, und dass Unterklassen nur bestimmte Funktionen implementieren müssen, die ihnen entsprechen. Dabei wird für eine Schnittstelle nur angegeben, welche Aufgaben ausgeführt werden müssen, und von der Schnittstelle werden keine Implementierungen angegeben. Ich kann sagen, dass es den Vertrag zwischen sich selbst und implementierten Klassen spezifiziert.
quelle
Sogar ich habe in mehreren Interviews dieselbe Frage gestellt und glaube mir, es macht Ihre Zeit miserabel, den Interviewer zu überzeugen. Wenn ich alle Antworten von oben inhärent habe, muss ich einen weiteren wichtigen Punkt hinzufügen, um es überzeugender zu machen und OO optimal zu nutzen
Falls Sie keine Änderung der Regeln planen für die Unterklasse für eine lange Zukunft folgen, werden, gehen Sie für die Schnittstelle, wie sie in ihn ändern können, werde nicht und wenn Sie dies tun, müssen Sie für die gehen Änderungen in allen anderen Unterklassen. Wenn Sie jedoch der Meinung sind, dass Sie die Funktionalität wiederverwenden, einige Regeln festlegen und sie auch für Änderungen öffnen möchten, wählen Sie die abstrakte Klasse.
Denken Sie auf diese Weise, Sie haben einen Verbrauchsdienst verwendet oder der Welt einen Code zur Verfügung gestellt, und Sie haben die Möglichkeit, etwas zu ändern. Nehmen Sie eine Sicherheitsüberprüfung an. Wenn ich ein Verbraucher des Codes bin und eines Morgens nach einem Update, ich Finde alle Lesemarken in meiner Eclipse, die gesamte Anwendung ist ausgefallen. Um solche Albträume zu vermeiden, verwenden Sie Abstract over Interfaces
Ich denke, dies könnte den Interviewer in gewissem Maße überzeugen ... Happy Interviews Ahead.
quelle
Wenn ich versuche, das Verhalten zwischen zwei eng verwandten Klassen zu teilen, erstelle ich eine abstrakte Klasse, die das gemeinsame Verhalten enthält und beiden Klassen als übergeordnetes Element dient.
Wenn ich versuche, einen Typ zu definieren, eine Liste von Methoden, auf die ein Benutzer meines Objekts zuverlässig zugreifen kann, erstelle ich eine Schnittstelle.
Zum Beispiel würde ich niemals eine abstrakte Klasse mit einer konkreten Unterklasse erstellen, da es in abstrakten Klassen um das Teilen von Verhalten geht. Aber ich könnte sehr gut eine Schnittstelle mit nur einer Implementierung erstellen. Der Benutzer meines Codes weiß nicht, dass es nur eine Implementierung gibt. In einer zukünftigen Version gibt es möglicherweise mehrere Implementierungen, die alle Unterklassen einer neuen abstrakten Klasse sind, die beim Erstellen der Schnittstelle noch nicht vorhanden waren.
Das mag auch ein bisschen zu buchstäblich gewesen sein (obwohl ich noch nie gesehen habe, dass es irgendwo so steht, wo ich mich erinnere). Wenn der Interviewer (oder das OP) wirklich mehr von meiner persönlichen Erfahrung dazu haben wollte, wäre ich mit Anekdoten einer Schnittstelle fertig geworden, die sich aus der Notwendigkeit heraus entwickelt hat und umgekehrt.
Eine Sache noch. Mit Java 8 können Sie jetzt Standardcode in eine Schnittstelle einfügen und so die Grenze zwischen Schnittstellen und abstrakten Klassen weiter verwischen. Aber nach allem, was ich gesehen habe, wird diese Funktion selbst von den Herstellern der Java-Kernbibliotheken überbeansprucht. Diese Funktion wurde zu Recht hinzugefügt, um die Erweiterung einer Schnittstelle zu ermöglichen, ohne dass eine binäre Inkompatibilität entsteht. Wenn Sie jedoch einen brandneuen Typ erstellen, indem Sie eine Schnittstelle definieren, sollte die Schnittstelle NUR eine Schnittstelle sein. Wenn Sie auch gemeinsamen Code bereitstellen möchten, erstellen Sie auf jeden Fall eine Hilfsklasse (abstrakt oder konkret). Überladen Sie Ihre Benutzeroberfläche nicht von Anfang an mit Funktionen, die Sie möglicherweise ändern möchten.
quelle
Der grundlegende Unterschied zwischen Schnittstelle und abstrakter Klasse besteht darin, dass die Schnittstelle Mehrfachvererbung unterstützt, die abstrakte Klasse jedoch nicht.
In der abstrakten Klasse können Sie auch alle abstrakten Methoden wie die Schnittstelle bereitstellen.
Warum ist eine abstrakte Klasse erforderlich?
In einigen Szenarien weiß die abstrakte Klasse während der Verarbeitung der Benutzeranforderung nicht, welche Benutzerabsicht vorliegt. In diesem Szenario definieren wir eine abstrakte Methode in der Klasse und bitten den Benutzer, der diese Klasse erweitert, Ihre Absicht in der abstrakten Methode anzugeben. In diesem Fall sind abstrakte Klassen sehr nützlich
Warum ist eine Schnittstelle erforderlich?
Nehmen wir an, ich habe eine Arbeit, die ich in diesem Bereich nicht erlebt habe. Wenn Sie beispielsweise ein Gebäude oder einen Damm bauen möchten, was werden Sie dann in diesem Szenario tun?
Hier kümmere ich mich nicht um die Logik, wie sie aufgebaut sind. Das endgültige Objekt hat meine Anforderungen erfüllt oder nicht, das ist nur mein zentraler Punkt.
Hier werden Ihre Anforderungen, die als Schnittstelle und Konstruktoren bezeichnet werden, als Implementierer bezeichnet.
quelle
In wenigen Worten würde ich folgendermaßen antworten:
Abstrakte Klassen können als etwas zwischen diesen beiden Fällen behandelt werden (es führt einen gewissen Status ein, verpflichtet Sie aber auch, ein Verhalten zu definieren). Eine vollständig abstrakte Klasse ist eine Schnittstelle (dies ist eine Weiterentwicklung von Klassen, die nur in C ++ as aus virtuellen Methoden bestehen soweit mir die Syntax bekannt ist).
Ab Java 8 haben sich die Dinge natürlich leicht geändert, aber die Idee ist immer noch dieselbe.
Ich denke, das ist hübsch genug für ein typisches Java-Interview, wenn Sie nicht mit einem Compiler-Team interviewt werden.
quelle
Soweit ich weiß, wird eine Schnittstelle, die aus endgültigen Variablen und Methoden ohne Implementierung besteht, von einer Klasse implementiert, um eine Gruppe von Methoden oder Methoden zu erhalten, die miteinander in Beziehung stehen. Andererseits wird eine abstrakte Klasse, die nicht endgültige Variablen und Methoden mit Implementierungen enthalten kann, normalerweise als Leitfaden oder als Oberklasse verwendet, von der alle verwandten oder ähnlichen Klassen erben. Mit anderen Worten, eine abstrakte Klasse enthält alle Methoden / Variablen, die von allen Unterklassen gemeinsam genutzt werden.
quelle
In der abstrakten Klasse können Sie die Standardimplementierung von Methoden schreiben! Aber in Interface kann man nicht. Grundsätzlich gibt es in der Schnittstelle rein virtuelle Methoden, die von der Klasse implementiert werden müssen, die die Schnittstelle implementiert.
quelle
Ja, Ihre Antworten waren technisch korrekt, aber wenn Sie einen Fehler gemacht haben, haben Sie nicht gezeigt, dass Sie die Vor- und Nachteile der Auswahl übereinander verstehen. Darüber hinaus waren sie wahrscheinlich besorgt / ausgeflippt über die Kompatibilität ihrer Codebasis mit zukünftigen Upgrades. Diese Art der Antwort hat möglicherweise geholfen (zusätzlich zu dem, was Sie gesagt haben):
Viel Glück bei deinem nächsten Interview!
quelle
Ich werde versuchen, anhand eines praktischen Szenarios zu antworten, um die Unterscheidung zwischen den beiden zu zeigen.
Schnittstellen haben keine Nutzlast, dh es muss kein Status beibehalten werden. Daher ist es besser, nur einen Vertrag (eine Fähigkeit) mit einer Klasse zu verknüpfen.
Angenommen, ich habe eine Task-Klasse, die eine Aktion ausführt. Um eine Task in einem separaten Thread auszuführen, muss die Thread-Klasse nicht wirklich erweitert werden. Eine bessere Wahl besteht darin, die Task Runnable-Schnittstelle implementieren zu lassen (dh ihre run () -Methode zu implementieren ) und übergeben Sie dann das Objekt dieser Task-Klasse an eine Thread-Instanz und rufen Sie deren start () -Methode auf.
Nun, technisch war das möglich, aber in Bezug auf das Design wäre dies ein schlechter Grund gewesen:
Mit anderen Worten, die Task-Klasse benötigte die Fähigkeit, in einem Thread ausgeführt zu werden, was durch die Implementierung von Runnable-Schnittstellenversen erreicht wurde, die die Thread-Klasse erweitern, die sie zu einem Thread machen würde.
Haftungsausschluss: Dummes Beispiel folgt, versuchen Sie nicht zu beurteilen :-P
Jetzt haben Sie die Wahl, gottähnlich zu sein, aber Sie können sich dafür entscheiden, nur Vergebender zu sein (dh nicht gottähnlich) und Folgendes zu tun:
Oder Sie entscheiden sich dafür, gottähnlich zu sein und Folgendes zu tun:
PS mit Java 8-Schnittstelle kann auch über statische Standardmethoden (überschreibbare Implementierung) verfügen, sodass der Unterschied zwischen der s / w-Schnittstelle und der abstrakten Klasse noch weiter eingegrenzt wird.
quelle
Fast alles scheint hier bereits behandelt zu sein. Noch ein Punkt zur praktischen Umsetzung des
abstract
Unterrichts:quelle
hmm jetzt sind die Leute hungrig praktischer Ansatz, Sie haben ganz recht, aber die meisten Interviewer sehen nach ihren aktuellen Anforderungen aus und wollen einen praktischen Ansatz.
Nachdem Sie Ihre Antwort beendet haben, sollten Sie auf das Beispiel springen:
Abstrakt:
Zum Beispiel haben wir eine Gehaltsfunktion, die allen Mitarbeitern einige Parameter gemeinsam hat. Dann können wir eine abstrakte Klasse namens CTC mit einem teilweise definierten Methodenkörper haben, die von allen Arten von Mitarbeitern erweitert und gemäß ihren zusätzlichen Vorteilen neu definiert wird. Für die allgemeine Funktionalität.
Schnittstelle
Die Benutzeroberfläche in Java ermöglicht die Verwendung von Schnittstellenfunktionen, ohne diese zu erweitern, und Sie müssen mit der Implementierung der Signatur der Funktionen, die Sie in Ihre Anwendung einführen möchten, klar sein. es wird dich zwingen, eine Definition zu haben. Für unterschiedliche Funktionen.
Sie können eine solche erzwungene Aktivität auch mit abstrakter Klasse haben, indem Sie Methgos als abstrakte definieren. Jetzt erweitert eine Klasse die abstrakte Klasse, die abstrakt ist, bis sie diese abstrakte Funktion überschreibt.
quelle
Nach dem, was ich verstehe und wie ich mich nähere,
Die Schnittstelle ist wie eine Spezifikation / ein Vertrag. Jede Klasse, die eine Schnittstellenklasse implementiert, muss alle in der abstrakten Klasse definierten Methoden implementieren (mit Ausnahme der in Java 8 eingeführten Standardmethoden).
Während ich eine Klassenzusammenfassung definiere, wenn ich die Implementierung kenne, die für einige Methoden der Klasse erforderlich ist, und einige Methoden, weiß ich immer noch nicht, was die Implementierung sein wird (wir kennen möglicherweise die Funktionssignatur, aber nicht die Implementierung). Ich mache das so, dass ich später im Teil der Entwicklung, wenn ich weiß, wie diese Methoden implementiert werden sollen, diese abstrakte Klasse einfach erweitern und diese Methoden implementieren kann.
Hinweis: In Schnittstellenmethoden kann kein Funktionskörper vorhanden sein, es sei denn, die Methode ist statisch oder standardmäßig.
quelle
Ich glaube, was der Interviewer versuchte zu erreichen, war wahrscheinlich der Unterschied zwischen Schnittstelle und Implementierung.
Die Schnittstelle - keine Java-Schnittstelle, sondern allgemeiner "Schnittstelle" - zu einem Codemodul ist im Grunde der Vertrag mit Client-Code, der die Schnittstelle verwendet.
Die Implementierung eines Codemoduls ist der interne Code, mit dem das Modul funktioniert. Oft können Sie eine bestimmte Schnittstelle auf mehrere verschiedene Arten implementieren und sogar die Implementierung ändern, ohne dass der Clientcode die Änderung überhaupt bemerkt.
Eine Java-Schnittstelle sollte nur als Schnittstelle im oben genannten allgemeinen Sinne verwendet werden, um zu definieren, wie sich die Klasse zum Nutzen des Clientcodes unter Verwendung der Klasse verhält, ohne eine Implementierung anzugeben. Daher enthält eine Schnittstelle Methodensignaturen - die Namen, Rückgabetypen und Argumentlisten - für Methoden, von denen erwartet wird, dass sie vom Clientcode aufgerufen werden, und sollte im Prinzip reichlich Javadoc für jede Methode enthalten, die beschreibt, was diese Methode tut. Der überzeugendste Grund für die Verwendung einer Schnittstelle ist, wenn Sie mehrere verschiedene Implementierungen der Schnittstelle planen und möglicherweise abhängig von der Bereitstellungskonfiguration eine Implementierung auswählen.
Im Gegensatz dazu bietet eine abstrakte Java-Klasse eine teilweise Implementierung der Klasse, anstatt den primären Zweck zu haben, eine Schnittstelle anzugeben. Es sollte verwendet werden, wenn mehrere Klassen Code gemeinsam nutzen, aber auch erwartet wird, dass die Unterklassen einen Teil der Implementierung bereitstellen. Auf diese Weise kann der gemeinsam genutzte Code nur an einer Stelle angezeigt werden - der abstrakten Klasse - und es wird klargestellt, dass Teile der Implementierung nicht in der abstrakten Klasse vorhanden sind und voraussichtlich von Unterklassen bereitgestellt werden.
quelle
Ihre Antwort ist richtig, aber der Interviewer muss Sie nach der Perspektive des Software-Engineerings unterscheiden, nicht nach den Details von Java.
Einfache Worte:
Eine Schnittstelle ist wie die Schnittstelle eines Shops. Alles, was darauf angezeigt wird, sollte sich im Shop befinden. Daher muss jede Methode in der Schnittstelle dort in der konkreten Klasse implementiert sein. Was ist nun, wenn einige Klassen einige genaue Methoden teilen und in anderen variieren? Angenommen, das Interface handelt von einem Geschäft, das zwei Dinge enthält, und angenommen, wir haben zwei Geschäfte, die beide Sportgeräte enthalten, aber eines hat zusätzliche Kleidung und das andere zusätzliche Schuhe. Sie erstellen also eine abstrakte Klasse für Sport, die die Sportmethode implementiert und die andere Methode nicht implementiert. Abstrakte Klasse bedeutet hier, dass dieser Shop selbst nicht existiert, aber die Basis für andere Klassen / Shops ist. Auf diese Weise organisieren Sie den Code, vermeiden Fehler beim Replizieren des Codes, vereinheitlichen den Code und stellen die Wiederverwendbarkeit durch eine andere Klasse sicher.
quelle