538 Stimmen

Wie sollte ich den Unterschied zwischen einem Interface und einer abstrakten Klasse erklärt haben?

In einem meiner Interviews wurde ich gebeten, den Unterschied zwischen einem Interface und einer abstrakten Klasse zu erklären.

Hier ist meine Antwort:

Methoden eines Java-Interfaces sind implizit abstrakt und können nicht implementiert werden. Eine Java-abstrakte Klasse kann Instanzmethoden haben, die ein Standardverhalten implementieren.

In einem Java-Interface deklarierte Variablen sind standardmäßig final. Eine abstrakte Klasse kann nicht-finale Variablen enthalten.

Elemente eines Java-Interfaces sind standardmäßig öffentlich. Eine Java-abstrakte Klasse kann die üblichen Arten von Klassenelementen wie private, geschützte usw. haben.

Ein Java-Interface sollte mit dem Schlüsselwort "implements" implementiert werden; Eine Java-abstrakte Klasse sollte mit dem Schlüsselwort "extends" erweitert werden.

Ein Interface kann nur ein anderes Java-Interface erweitern, eine abstrakte Klasse kann eine andere Java-Klasse erweitern und mehrere Java-Interfaces implementieren.

Eine Java-Klasse kann mehrere Interfaces implementieren, aber nur eine abstrakte Klasse erweitern.

Der Interviewer war jedoch nicht zufrieden und sagte mir, dass diese Beschreibung "buchhalterisches Wissen" widerspiegelte.

Er bat mich um eine praktischere Antwort und erklärte, wann ich eine abstrakte Klasse anstelle eines Interfaces wählen würde, unter Verwendung praktischer Beispiele.

Wo habe ich einen Fehler gemacht?

568voto

Vimal Bera Punkte 10346

Ich gebe Ihnen zuerst ein Beispiel:

public interface LoginAuth{
   public String encryptPassword(String pass);
   public void checkDBforUser();
}

Angenommen, Sie haben 3 Datenbanken in Ihrer Anwendung. Dann muss jede Implementierung für diese Datenbank die oben genannten 2 Methoden definieren:

public class DBMySQL implements LoginAuth{
          // Muss beide Methoden implementieren
}
public class DBOracle implements LoginAuth{
          // Muss beide Methoden implementieren
}
public class DBAbc implements LoginAuth{
          // Muss beide Methoden implementieren
}

Aber was ist, wenn encryptPassword() nicht datenbankabhängig ist und für jede Klasse gleich ist? Dann wäre der obige Ansatz nicht gut.

Stattdessen können Sie diesen Ansatz in Betracht ziehen:

public abstract class LoginAuth{
   public String encryptPassword(String pass){
            // Implementieren Sie das gleiche Standardverhalten hier 
            // das von allen Unterklassen gemeinsam genutzt wird.
   }

   // Jede Unterklasse muss nur ihre eigene Implementierung dieser Methode bereitstellen:
   public abstract void checkDBforUser();
}

Jetzt müssen wir in jeder Kindklasse nur eine Methode implementieren - die Methode, die von der Datenbank abhängig ist.

225voto

Shailesh Saxena Punkte 3422

Nichts ist perfekt in dieser Welt. Vielleicht haben sie mehr von einem praktischen Ansatz erwartet.

Aber nach Ihrer Erklärung könnten Sie diese Zeilen mit einem etwas anderen Ansatz hinzufügen.

  1. Interfaces sind Regeln (Regeln, weil Sie ihnen eine Implementierung geben müssen, die Sie nicht ignorieren oder vermeiden können, so dass sie wie Regeln durchgesetzt werden), die als gemeinsames Verständigungsdokument zwischen verschiedenen Teams in der Softwareentwicklung dienen.

  2. Interfaces geben eine Vorstellung davon, was zu tun ist, aber nicht wie es getan wird. Die Implementierung hängt also komplett vom Entwickler ab, indem er die gegebenen Regeln befolgt (d.h. die gegebene Signatur von Methoden).

  3. Abstrakte Klassen können abstrakte Deklarationen, konkrete Implementierungen oder beides enthalten.

  4. 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 eine eigene Implementierung erstellt).

  5. Außerdem werden Methoden mit derselben Signatur, die sich je nach Kontext anders verhalten können, als Schnittstellen-Deklarationen als Regeln bereitgestellt, um entsprechend in verschiedenen Kontexten implementiert zu werden.

Bearbeiten: Java 8 ermöglicht die Definition von Standard- und statischen Methoden in Interfaces.

public interface SomeInterfaceOne {

    void usualAbstractMethod(String inputString);

    default void defaultMethod(String inputString){
        System.out.println("Innerhalb von SomeInterfaceOne defaultMethod::"+inputString);
    }
}

Wenn eine Klasse nun SomeInterface implementiert, ist es nicht zwingend erforderlich, eine Implementierung für Standardmethoden des Interfaces bereitzustellen.

Wenn wir ein weiteres Interface mit den folgenden Methoden haben:

public interface SomeInterfaceTwo {

    void usualAbstractMethod(String inputString);

    default void defaultMethod(String inputString){
        System.out.println("Innerhalb von SomeInterfaceTwo defaultMethod::"+inputString);
    }

}

Java erlaubt nicht die Vererbung mehrerer Klassen, da dies zum "Diamantenproblem" führt, bei dem der Compiler nicht entscheiden kann, welche Methoden der Superklasse verwendet werden sollen. Mit den Standardmethoden tritt das Diamantenproblem auch bei Schnittstellen auf. Denn wenn eine Klasse sowohl

SomeInterfaceOne als auch SomeInterfaceTwo

implementiert und die gemeinsame Standardmethode nicht implementiert, kann der Compiler nicht entscheiden, welche Methode gewählt werden soll. Um dieses Problem zu vermeiden, ist es in Java 8 erforderlich, die gemeinsamen Standardmethoden verschiedener Interfaces zu implementieren. Wenn eine Klasse beide oben genannten Interfaces implementiert, muss sie eine Implementierung der defaultMethod() Methode bereitstellen, sonst wirft der Compiler einen Kompilierungsfehler.

197voto

Daniel Lerps Punkte 5134

Du hast eine gute Zusammenfassung der praktischen Unterschiede in der Verwendung und Implementierung gemacht, aber nichts über den Unterschied in der Bedeutung gesagt.

Ein Interface ist eine Beschreibung des Verhaltens, das eine implementierende Klasse haben wird. Die implementierende Klasse stellt sicher, dass sie über diese Methoden verfügt, die auf ihr verwendet werden können. Es handelt sich im Grunde genommen um einen Vertrag oder ein Versprechen, das die Klasse abgeben muss.

Eine abstrakte Klasse ist die Grundlage für verschiedene Unterklassen, die Verhaltensweisen teilen, die nicht wiederholt erstellt werden müssen. Unterklassen müssen das Verhalten vervollständigen und haben die Möglichkeit, vordefiniertes Verhalten zu überschreiben (solange es nicht als final oder private definiert ist).

Gute Beispiele finden Sie im Paket java.util, das Schnittstellen wie List und abstrakte Klassen wie AbstractList enthält, die die Schnittstelle bereits implementieren. Die offizielle Dokumentation beschreibt die AbstractList wie folgt:

Diese Klasse bietet eine skelettierte Implementierung des List-Interfaces, um den Aufwand zu minimieren, der erforderlich ist, um dieses Interface zu implementieren, das von einem "Random Access"-Daten speicher unterstützt wird (wie z. B. ein Array).

98voto

Satya Punkte 1011

Ein Interface besteht aus Singleton-Variablen (public static final) und öffentlichen abstrakten Methoden. Wir nutzen normalerweise ein Interface in Echtzeit, wenn wir wissen was zu tun ist, aber nicht wissen, wie es zu tun ist.

Dieses Konzept kann am besten durch ein Beispiel verstanden werden:

Betrachten Sie eine Zahlungsklasse. Zahlungen können auf viele verschiedene Arten erfolgen, wie z.B. PayPal, Kreditkarte usw. Deshalb nehmen wir normalerweise Zahlung als unser Interface, das eine makePayment()-Methode enthält, und Kreditkarte und PayPal sind die beiden Implementierungsklassen.

public interface Payment
{
    void makePayment(); // Standardmäßig ist dies eine abstrakte Methode
}
public class PayPal implements Payment
{
    public void makePayment()
    {
        // irgendeine Logik für PayPal-Zahlung
        // z.B. PayPal verwendet Benutzername und Passwort für die Zahlung
    }
}
public class Kreditkarte implements Zahlung
{
    public void makePayment()
    {
        // irgendeine Logik für Kreditkartenzahlung
        // z.B. Kreditkarte verwendet Kartennummer, Ablaufdatum usw...
    }
}

In obigem Beispiel sind Kreditkarte und PayPal zwei Implementierungsklassen/Strategien. Ein Interface erlaubt uns auch das Konzept der Mehrfachvererbung in Java, was mit einer abstrakten Klasse nicht möglich ist.

Wir wählen eine abstrakte Klasse, wenn wir einige Funktionen haben, für die wir wissen, was zu tun ist, und andere Funktionen, die wir wissen, wie sie durchzuführen sind.

Betrachten Sie das folgende Beispiel:

public abstract class Burger
{
    public void packing()
    {
        // irgendeine Logik für das Verpacken eines Burgers
    }
    public abstract void price(); // Der Preis ist für verschiedene Kategorien von Burgern unterschiedlich
}
public class VegBurger extends Burger
{
    public void price()
    {
        // Preis für einen vegetarischen Burger festlegen.
    }
}
public class NonVegBurger extends Burger
{
    public void price()
    {
        // Preis für einen nicht-vegetarischen Burger festlegen.
    }
}

Wenn wir in Zukunft Methoden (konkret/abstrakt) zu einer gegebenen abstrakten Klasse hinzufügen, muss die Implementierungsklasse ihren Code nicht ändern. Wenn wir jedoch in Zukunft Methoden zu einem Interface hinzufügen, müssen wir Implementierungen zu allen Klassen hinzufügen, die dieses Interface implementiert haben, da sonst Kompilierungsfehler auftreten.

Es gibt weitere Unterschiede, aber dies sind die wichtigsten, die möglicherweise das waren, was Ihr Interviewer erwartet hat. Hoffentlich war das hilfreich.

24voto

VictorCreator Punkte 724

Deine Erklärung sieht vernünftig aus, aber vielleicht schien es, als würdest du alles aus einem Lehrbuch ablesen? :-/

Was mich mehr beunruhigt, ist, wie solide dein Beispiel war. Hast du dich bemüht, fast alle Unterschiede zwischen abstrakten Klassen und Schnittstellen einzuschließen?

Persönlich würde ich diesen Link vorschlagen: http://mindprod.com/jgloss/interfacevsabstract.html#TABLE

für eine umfassende Liste von Unterschieden..

Hoffe es hilft dir und allen anderen Lesern bei ihren zukünftigen Interviews

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X