In einem meiner Interviews wurde ich gebeten, den Unterschied zwischen einer Schnittstelle und einer abstrakten Klasse zu erklären.
Hier's meine Antwort:
Methoden einer Java-Schnittstelle sind implizit abstrakt und können keine Implementierungen haben. Eine abstrakte Java-Klasse kann Instanzmethoden haben, die ein Standardverhalten implementieren.
Variablen, die in einer Java-Schnittstelle deklariert sind, sind standardmäßig final. Eine abstrakte Klasse kann nicht-finale Variablen enthalten.
Die Mitglieder einer Java-Schnittstelle sind standardmäßig öffentlich. Eine abstrakte Java Klasse kann die üblichen Arten von Klassenmitgliedern haben, wie private, geschützt, etc.
Eine Java-Schnittstelle sollte mit dem Schlüsselwort "implements" implementiert werden; eine Java abstrakte Klasse sollte mit dem Schlüsselwort "extends" 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 sie kann nur eine abstrakte Klasse erweitern. eine abstrakte Klasse erweitern.
Der Interviewer war jedoch nicht zufrieden und sagte mir, dass diese Beschreibung "Buchwissen" darstellt.
Er bat mich um eine praktischere Antwort, in der ich anhand von praktischen Beispielen erklären sollte, wann ich eine abstrakte Klasse einer Schnittstelle vorziehen würde.
Was habe ich falsch gemacht?
Nichts ist perfekt in dieser Welt. Vielleicht haben sie eher einen praktischen Ansatz erwartet.
Aber nach Ihrer Erklärung könnten Sie diese Zeilen mit einem etwas anderen Ansatz hinzufügen.
Schnittstellen sind Regeln (Regeln, weil man ihnen eine Implementierung geben muss, die man nicht ignorieren oder umgehen kann, so dass sie wie Regeln auferlegt werden), die als gemeinsames Verständnisdokument zwischen verschiedenen Teams in der Softwareentwicklung funktionieren.
Schnittstellen geben die Idee, was zu tun ist, aber nicht, wie es getan wird. Die Implementierung hängt also vollständig vom Entwickler ab, der sich an die vorgegebenen Regeln hält (d.h. an die vorgegebene 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 (man kann sie so verwenden, wie sie sind, oder man kann sie ignorieren, indem man sie überschreibt und ihnen seine eigene Implementierung gibt).
Außerdem werden die Methoden mit gleicher Signatur, die das Verhalten in verschiedenen Kontexten ändern können, als Schnittstellendeklarationen als Regeln bereitgestellt, die in verschiedenen Kontexten entsprechend zu implementieren sind.
Bearbeitung: Java 8 erleichtert die Definition von Standard- und statischen Methoden in Schnittstellen.
public interface SomeInterfaceOne {
void usualAbstractMethod(String inputString);
default void defaultMethod(String inputString){
System.out.println("Inside SomeInterfaceOne defaultMethod::"+inputString);
}
}
Wenn eine Klasse nun SomeInterface implementiert, ist es nicht zwingend erforderlich, eine Implementierung für Standardmethoden der Schnittstelle bereitzustellen.
Wenn wir eine andere Schnittstelle mit den folgenden Methoden haben:
public interface SomeInterfaceTwo {
void usualAbstractMethod(String inputString);
default void defaultMethod(String inputString){
System.out.println("Inside SomeInterfaceTwo defaultMethod::"+inputString);
}
}
Java erlaubt es nicht, mehrere Klassen zu erweitern, da dies zu dem "Diamantproblem " führt, bei dem der Compiler nicht entscheiden kann, welche Methode der Oberklasse verwendet werden soll. Mit den Standardmethoden wird das Diamantenproblem auch für Schnittstellen auftreten. Denn wenn eine Klasse sowohl
SomeInterfaceOne and SomeInterfaceTwo
implementiert und die gemeinsame Standardmethode nicht implementiert, kann der Compiler nicht entscheiden, welche Methode er wählen soll. Um dieses Problem zu vermeiden, ist es in Java 8 obligatorisch, gemeinsame Standardmethoden verschiedener Schnittstellen zu implementieren. Wenn eine Klasse beide oben genannten Schnittstellen implementiert, muss sie eine Implementierung für die defaultMethod()-Methode bereitstellen, andernfalls wird der Compiler einen Kompilierzeitfehler ausgeben.
Deine Erklärung sieht gut aus, aber vielleicht sah es so aus, als ob du alles aus einem Lehrbuch ablesen würdest :-/
Was mich mehr stört, ist, wie solide war Ihr Beispiel? Haben Sie sich die Mühe gemacht, fast alle Unterschiede zwischen abstrakten und Schnittstellen zu erläutern?
Ich persönlich würde diesen Link vorschlagen: http://mindprod.com/jgloss/interfacevsabstract.html#TABLE
für eine erschöpfende Liste der Unterschiede...
Ich hoffe, es hilft Ihnen und allen anderen Lesern bei ihren zukünftigen Gesprächen
Eine Schnittstelle ist ein Vertrag, in dem sich die Klasse, die den Vertrag implementiert, verpflichtet, die Methoden zu implementieren. Ein Beispiel, bei dem ich eine Schnittstelle anstelle einer Klasse schreiben musste, war, als ich ein Spiel von 2D auf 3D aktualisierte. Ich musste eine Schnittstelle für die gemeinsame Nutzung von Klassen in der 2D- und der 3D-Version des Spiels erstellen.
package adventure;
import java.awt.*;
public interface Playable {
public void playSound(String s);
public Image loadPicture(String s);
}
Dann kann ich die Methoden basierend auf der Umgebung implementieren, während ich immer noch in der Lage bin, diese Methoden von einem Objekt aufzurufen, das nicht weiß, welche Version des Spiels gerade geladen wird.
public class Adventure extends JFrame implementiert Playable
public class Dungeon3D extends SimpleApplication implements Playable
public class Main extends SimpleApplication implements AnimEventListener, ActionListener, Abspielbar`
Typischerweise kann die Welt in der Spielwelt eine abstrakte Klasse sein, die Methoden für das Spiel ausführt:
public abstract class World...
public Playable owner;
public Playable getOwner() {
return owner;
}
public void setOwner(Playable owner) {
this.owner = owner;
}