Wie hätte ich den Unterschied zwischen einer Interface- und einer Abstract-Klasse erklären sollen?


469

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?


32
Vielleicht sah Ihre Antwort so aus, als würden Sie etwas erzählen, das Sie nicht verstehen? Es kann sein, dass Sie einfach den Erzählstil auf den ändern müssen, der mehr wie Ihre eigenen Worte aussieht.
Kirill Kobelev

19
Sie antworteten mit einer Liste (ganz korrekter) technischer Unterschiede. Der Interviewer suchte höchstwahrscheinlich nach einer konzeptionelleren Antwort (z. B. auf welcher Grundlage man zwischen der Verwendung einer Schnittstelle und einer abstrakten Klasse wählen würde).
Ted Hopp

15
Sie haben vergessen zu sagen, dass abstrakte Klassen Konstruktoren haben, obwohl Sie eine abstrakte Klasse, die const, nicht instanziieren können. wird von untergeordneten Klassen verwendet. Schnittstellen geben "was" an, aber nicht "wie", da sie einen Vertrag (Liste der Methoden) definieren, während sie sich enthalten. Klasse kann auch "wie" angeben (eine Methode implementieren). Mit int. Sie können mehrere Vererbungen emulieren (eine Klasse kann mehrere int implementieren, aber nur eine Klasse erweitern). Mit int. Sie können einen Basistyp für dif haben. Familien: Flyer f = neues Flugzeug (); Flyer f2 = neuer Vogel (); Vogel und Flugzeug entsprechen nicht derselben Familie, aber beide können fliegen (sind Flyer).
Francisco Goldenstein

7
Ab Java8 können Schnittstellen Methoden enthalten. Über das OO-Konzept hinaus können sich diese sogenannten "Unterschiede" jeden Tag ändern.
Ringträger

15
Ich habe kein Problem mit Ihrer Antwort, und ich glaube nicht, dass der Interviewer etwas damit zu tun hat, sich über "Buchwissen" lustig zu machen. Interviewer kennen nicht immer die richtigen Antworten auf die Fragen, die sie stellen, und einige Interviews dienen nur dazu, Sie zu warnen, dort nicht zu arbeiten.
Marquis von Lorne

Antworten:


513

Ich werde Ihnen zuerst ein Beispiel geben:

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

Angenommen, Ihre Anwendung enthält 3 Datenbanken. Dann muss jede Implementierung für diese Datenbank die beiden oben genannten Methoden definieren:

public class DBMySQL implements LoginAuth{
          // Needs to implement both methods
}
public class DBOracle implements LoginAuth{
          // Needs to implement both methods
}
public class DBAbc implements LoginAuth{
          // Needs to implement both methods
}

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:

public abstract class LoginAuth{
   public String encryptPassword(String pass){
            // Implement the same default behavior here 
            // that is shared by all subclasses.
   }

   // Each subclass needs to provide their own implementation of this only:
   public abstract void checkDBforUser();
}

Jetzt müssen wir in jeder untergeordneten Klasse nur noch eine Methode implementieren - die datenbankabhängige Methode.


97
Ich bin mir nicht sicher, ob dies den Unterschied wirklich erklärt ... sicher, dass es eine schöne Technik ist. Ich nehme an, es ist auch erwähnenswert, dass Java 8 endlich zugegeben hat, dass C ++ richtig war und dass Mehrfachvererbung durchgeführt werden kann und eine Verwendung haben kann, sodass Schnittstellen jetzt nicht nur Funktionssignaturen definieren, sondern auch Standardimplementierungen bereitstellen können. Daher wäre die Verwendung einer Schnittstelle vorzuziehen.
Thecoshman

1
@thecoshman Welchen Unterschied würde es machen, wenn ich mich dem Problem wie in der Antwort nähern würde (abstrakte Klasse mit einer implementierten Methode und der anderen abstrakten) oder eine Schnittstelle mit einer Standardmethodenimplementierung definieren würde? Grundsätzlich versuche ich zu sagen, dass Sie geschrieben haben, dass die Verwendung einer Schnittstelle vorzuziehen wäre, und meine Frage lautet: Warum?
Neutrino

1
Ich denke also, es ist fair zu sagen, dass bei Schnittstellen die Implementierung dessen, was definiert wurde, von der Klasse abhängt, die die Schnittstelle tatsächlich implementiert, während das Material in einer abstrakten Klasse für die Klassen, die die Klasse erweitern, "Kern" ist. dh es ändert sich nicht.
Orrymr

4
@Neutrino Obwohl Java es Ihnen ermöglicht, mehrere Schnittstellen zu implementieren, die jeweils Standardimplementierungen für Funktionen bieten, können Sie immer noch nur eine Klasse erweitern. Daher kann die Verwendung einer Schnittstelle zusammen mit anderen Schnittstellen mehr Flexibilität für diejenigen bieten, die sie verwenden möchten.
Thecoshman

3
@ HiradNikoo Entschuldigung für den späten Kommentar, aber ich bin gerade über diesen Thread gestolpert. Sie können die Klassenvererbung auch als IS-A-Beziehung betrachten, während Schnittstellen "eine bestimmte Funktionalität haben" bedeuten.
Alexander Jank

206

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.

  1. 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.

  2. 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).

  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 (Sie können sie so verwenden, wie sie sind, oder Sie können sie ignorieren, indem Sie sie überschreiben und Ihre eigene Implementierung geben).

  5. 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.

public interface SomeInterfaceOne {

    void usualAbstractMethod(String inputString);

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

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:

public interface SomeInterfaceTwo {

    void usualAbstractMethod(String inputString);

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

}

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

SomeInterfaceOne and SomeInterfaceTwo

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.


11
+1, das ist wirklich eine gute Antwort, um die Verwirrung zu vermeiden. Aber ich habe keinen Link gesehen und keine Ahnung, warum Sie diese wertvollen Zeilen zitiert haben. Machen Sie sie wenn möglich als Punkte :).
Suresh Atta

Lesen Sie meinen obigen Kommentar zum Emulieren der Mehrfachvererbung mithilfe von Schnittstellen und der Verwendung von Schnittstellen für einen Basistyp für Klassen verschiedener Familien. Ich denke, dass der Interviewer diese Art von Antworten vom Interview hören möchte.
Francisco Goldenstein

Ihr Kommentar weist auch auf ein gutes Beispiel für die Verwendung der Benutzeroberfläche hin. Ich schrieb, was ich fühle, wenn ich Tag für Tag arbeite. Diese Wörter sind möglicherweise nicht professionell oder korrekt. Aber es ist das, was ich erfahren habe, nachdem ich in meiner täglichen Codierung eng mit abstrakten Klassen und Schnittstellen zusammengearbeitet habe.
Shailesh Saxena

4. Konkrete Implementierungen sind auch die Regeln mit der Standardimplementierung.
Lauten

@Luten: Nach meinem Wissen, wenn Sie eine Regel ohne Probleme vermeiden / ignorieren können, muss dies eine Richtlinie sein, keine Regel. Bitte korrigieren Sie mich, wenn ich falsch liege.
Shailesh Saxena

168

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 finaloder definiert ist private).

Sie finden gute Beispiele in dem java.utilPaket, das Schnittstellen wie Listund abstrakte Klassen enthält, AbstractListdie die Schnittstelle bereits implementieren. Die offizielle Dokumentation beschreibt AbstractListFolgendes:

Diese Klasse bietet eine Skelettimplementierung der List-Schnittstelle, um den Aufwand für die Implementierung dieser Schnittstelle zu minimieren, die durch einen Datenspeicher mit "wahlfreiem Zugriff" (z. B. ein Array) unterstützt wird.


16
Dies sollte die Antwort sein. Keine Liste von Details, sondern das zugrunde liegende Konzept, das den Unterschied zwischen einer Schnittstelle und einer abstrakten Klasse ausmacht, nicht nur in Java, sondern allgemein.
edc65

1
Das ist sehr gut. Natürlich sind auch andere Antworten gut. Dies zeigt Ihnen jedoch ein wichtiges Heads-up zu abstractSchlü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 sie incomplete (abstract)Methoden haben mussten.
Rakib

85

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.

public interface Payment
{
    void makePayment();//by default it is a abstract method
}
public class PayPal implements Payment
{
    public void makePayment()
    {
        //some logic for PayPal payment
        //e.g. Paypal uses username and password for payment
    }
}
public class CreditCard implements Payment
{
    public void makePayment()
    {
        //some logic for CreditCard payment
        //e.g. CreditCard uses card number, date of expiry etc...
    }
}

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:

public abstract class Burger
{
    public void packing()
    {
        //some logic for packing a burger
    }
    public abstract void price(); //price is different for different categories of burgers
}
public class VegBerger extends Burger
{
    public void price()
    {
        //set price for a veg burger.
    }
}
public class NonVegBerger extends Burger
{
    public void price()
    {
        //set price for a non-veg burger.
    }
}

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.


1
Nun, diese Antwort macht sehr viel Sinn, und das Beispiel zeigt deutlich, wann wir zwischen interfaceund wählen abstract class.
MAC

"Was zu tun ist, aber nicht weiß, wie es zu tun ist", während wir eine Methode definieren, ohne darin Implementierungen vorzunehmen "void makePayment ();", während die Implementierungen der Methode in der Klasse definiert werden, die die Schnittstelle implementiert.
Abdel-Raouf

45

Unterschied zwischen Abstact-Klasse und Schnittstelle

  1. Abstrakte Klassen versus Schnittstellen in Java 8
  2. Konzeptioneller Unterschied:

Standardmethoden der Schnittstelle in Java 8

  1. Was ist die Standardmethode?
  2. Für jede Methode wurde ein Kompilierungsfehler mit der Standardmethode behoben
  3. Probleme mit der Standardmethode und Mehrdeutigkeit bei Mehrfachvererbung
  4. Wichtige Punkte zu den Standardmethoden der Java-Schnittstelle:

Statische Methode der Java-Schnittstelle

  1. Statische Methode der Java-Schnittstelle, Codebeispiel, statische Methode vs. Standardmethode
  2. Wichtige Punkte zur statischen Methode der Java-Schnittstelle:

Java-Funktionsschnittstellen



Abstrakte Klassen versus Schnittstellen in Java 8

Änderungen an der Java 8-Schnittstelle umfassen statische Methoden und Standardmethoden in Schnittstellen. Vor Java 8 konnten wir nur Methodendeklarationen in den Schnittstellen haben. Ab Java 8 können jedoch Standardmethoden und statische Methoden in den Schnittstellen vorhanden sein.

Nach der Einführung der Standardmethode scheinen Schnittstellen und abstrakte Klassen identisch zu sein. In Java 8 sind sie jedoch immer noch ein anderes Konzept.

Abstrakte Klasse kann Konstruktor definieren. Sie sind strukturierter und können mit einem Status verknüpft sein. Im Gegensatz dazu kann die Standardmethode nur durch Aufrufen anderer Schnittstellenmethoden implementiert werden, ohne dass auf den Status einer bestimmten Implementierung Bezug genommen wird. Daher hängt die Verwendung für verschiedene Zwecke und die Wahl zwischen zwei wirklich vom Szenariokontext ab.

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:

public interface OldInterface {
    public void existingMethod();
 
    default public void newDefaultMethod() {
        System.out.println("New default method"
               + " is added in interface");
    }
}

Die folgende Klasse wird erfolgreich in Java JDK 8 kompiliert:

public class OldInterfaceImpl implements OldInterface {
    public void existingMethod() {
     // existing implementation is here…
    }
}

Wenn Sie eine Instanz von OldInterfaceImpl erstellen:

OldInterfaceImpl obj = new OldInterfaceImpl ();
// print “New default method add in interface”
obj.newDefaultMethod(); 

Standardmethode:

Standardmethoden sind niemals endgültig, können nicht synchronisiert werden und können die Methoden von Object nicht überschreiben. Sie sind immer öffentlich, was die Fähigkeit, kurze und wiederverwendbare Methoden zu schreiben, stark einschränkt.

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.

Standardmethoden ermöglichen das Hinzufügen neuer Funktionen zu vorhandenen Schnittstellen, ohne die ältere Implementierung dieser Schnittstellen zu beschädigen.

Wenn wir eine Schnittstelle erweitern, die eine Standardmethode enthält, können wir Folgendes ausführen:

  1. Überschreiben Sie die Standardmethode nicht und erben Sie die Standardmethode.
  2. Überschreiben Sie die Standardmethode ähnlich wie andere Methoden, die wir in der Unterklasse überschreiben.
  3. Deklarieren Sie die Standardmethode erneut als abstrakt, wodurch die Unterklasse gezwungen wird, sie zu überschreiben.

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:

public interface Iterable<T> {
    public void forEach(Consumer<? super T> consumer);
}

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.

public interface Iterable<T> {
    public default void forEach(Consumer
                   <? super T> consumer) {
        for (T t : this) {
            consumer.accept(t);
        }
    }
}

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:

public interface InterfaceA {  
       default void defaultMethod(){  
           System.out.println("Interface A default method");  
    }  
}
 
public interface InterfaceB {
   default void defaultMethod(){
       System.out.println("Interface B default method");
   }
}
 
public class Impl implements InterfaceA, InterfaceB  {
}

Der obige Code kann mit dem folgenden Fehler nicht kompiliert werden:

java: class Impl erbt nicht verwandte Standardeinstellungen für defaultMethod () von den Typen InterfaceA und InterfaceB

Um diese Klasse zu reparieren, müssen wir die Standardmethodenimplementierung bereitstellen:

public class Impl implements InterfaceA, InterfaceB {
    public void defaultMethod(){
    }
}

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:

public class Impl implements InterfaceA, InterfaceB {
    public void defaultMethod(){
        // existing code here..
        InterfaceA.super.defaultMethod();
    }
}

Wir können im Rahmen unserer neuen Methode jede Standardimplementierung oder beides auswählen.

Wichtige Punkte zu den Standardmethoden der Java-Schnittstelle:

  1. Die Standardmethoden für Java-Schnittstellen helfen uns bei der Erweiterung von Schnittstellen, ohne befürchten zu müssen, Implementierungsklassen zu beschädigen.
  2. Die Standardmethoden für Java-Schnittstellen haben die Unterschiede zwischen Schnittstellen und abstrakten Klassen überbrückt.
  3. Die Standardmethoden der Java 8-Schnittstelle helfen uns dabei, Dienstprogrammklassen zu vermeiden, z. B. können alle Collections-Klassenmethoden in den Schnittstellen selbst bereitgestellt werden.
  4. Die Standardmethoden der Java-Schnittstelle helfen uns beim Entfernen von Basisimplementierungsklassen. Wir können die Standardimplementierung bereitstellen und die Implementierungsklassen können auswählen, welche überschrieben werden sollen.
  5. Einer der Hauptgründe für die Einführung von Standardmethoden in Schnittstellen ist die Erweiterung der Collections-API in Java 8 zur Unterstützung von Lambda-Ausdrücken.
  6. Wenn eine Klasse in der Hierarchie eine Methode mit derselben Signatur hat, sind Standardmethoden irrelevant. Eine Standardmethode kann eine Methode aus java.lang.Object nicht überschreiben. Die Argumentation ist sehr einfach, da Object die Basisklasse für alle Java-Klassen ist. Selbst wenn Objektklassenmethoden als Standardmethoden in Schnittstellen definiert sind, ist dies nutzlos, da immer die Objektklassenmethode verwendet wird. Um Verwirrung zu vermeiden, können wir keine Standardmethoden verwenden, die Objektklassenmethoden überschreiben.
  7. Standardmethoden für Java-Schnittstellen werden auch als Defender-Methoden oder virtuelle Erweiterungsmethoden bezeichnet.

Ressourcenlink:

  1. Schnittstelle mit Standardmethoden vs Abstract-Klasse in Java 8
  2. Abstrakte Klasse versus Schnittstelle in der JDK 8-Ära
  3. Schnittstellenentwicklung über virtuelle Erweiterungsmethoden

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.

public interface MyData {

    default void print(String str) {
        if (!isNull(str))
            System.out.println("MyData Print::" + str);
    }

    static boolean isNull(String str) {
        System.out.println("Interface Null Check");

        return str == null ? true : "".equals(str) ? true : false;
    }
}

Lassen Sie uns nun eine Implementierungsklasse sehen, die eine isNull () -Methode mit schlechter Implementierung hat.

public class MyDataImpl implements MyData {

    public boolean isNull(String str) {
        System.out.println("Impl Null Check");

        return str == null ? true : false;
    }

    public static void main(String args[]){
        MyDataImpl obj = new MyDataImpl();
        obj.print("");
        obj.isNull("abc");
    }
}

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.

Interface Null Check

Impl Null Check

Wenn wir die Schnittstellenmethode von statisch auf Standard setzen, erhalten wir folgende Ausgabe.

Impl Null Check

MyData Print ::

Impl Null Check

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:

boolean result = MyData.isNull("abc");

Wichtige Punkte zur statischen Methode der Java-Schnittstelle:

  1. Die statische Methode der Java-Schnittstelle ist Teil der Schnittstelle. Wir können sie nicht für Implementierungsklassenobjekte verwenden.
  2. Statische Methoden der Java-Schnittstelle eignen sich gut zur Bereitstellung von Dienstprogrammmethoden, z. B. Nullprüfung, Sortierung von Sammlungen usw.
  3. Die statische Methode der Java-Schnittstelle hilft uns bei der Bereitstellung von Sicherheit, indem Implementierungsklassen diese nicht überschreiben dürfen.
  4. Wir können keine statische Schnittstellenmethode für Objektklassenmethoden definieren. Wir erhalten den Compilerfehler "Diese statische Methode kann die Instanzmethode nicht vor Object verbergen". Dies liegt daran, dass dies in Java nicht zulässig ist, da Object die Basisklasse für alle Klassen ist und wir nicht über eine statische Methode auf Klassenebene und eine andere Instanzmethode mit derselben Signatur verfügen können.
  5. Wir können statische Methoden der Java-Schnittstelle verwenden, um Dienstprogrammklassen wie Sammlungen zu entfernen und alle statischen Methoden auf die entsprechende Schnittstelle zu verschieben, die leicht zu finden und zu verwenden wäre.

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 @FunctionalInterfacewurde eingeführt, um eine Schnittstelle als funktionale Schnittstelle zu markieren.@FunctionalInterfaceAnnotation 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:

  1. Java 8-Schnittstellenänderungen - statische Methode, Standardmethode

8
Ich suche genau nach solchen aktualisierten Antworten. Danke für die schnelle Antwort.
Ravindra Babu

41

Alle Ihre Anweisungen sind gültig, mit Ausnahme Ihrer ersten Anweisung (nach der Java 8-Version):

Methoden einer Java-Schnittstelle sind implizit abstrakt und können nicht implementiert werden

Aus der Dokumentation Seite :

Eine Schnittstelle ist ein Referenztyp, der einer Klasse ähnelt und nur Konstanten, Methodensignaturen, Standardmethoden, statische Methoden und verschachtelte Typen enthalten kann

Methodenkörper existieren nur für Standardmethoden und statische Methoden.

Standardmethoden:

Eine Schnittstelle kann Standardmethoden haben , unterscheidet sich jedoch von abstrakten Methoden in abstrakten Klassen.

Mit Standardmethoden können Sie den Schnittstellen Ihrer Bibliotheken neue Funktionen hinzufügen und die Binärkompatibilität mit Code sicherstellen, der für ältere Versionen dieser Schnittstellen geschrieben wurde.

Wenn Sie eine Schnittstelle erweitern, die eine Standardmethode enthält, können Sie Folgendes tun:

  1. Erwähnen Sie überhaupt nicht die Standardmethode, mit der Ihre erweiterte Schnittstelle die Standardmethode erben kann.
  2. Deklarieren Sie die Standardmethode neu, wodurch sie erstellt wird abstract.
  3. Definieren Sie die Standardmethode neu, die sie überschreibt.

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 interfaceHaben staticund defaultMethoden.

import java.time.*;

public interface TimeClient {
    void setTime(int hour, int minute, int second);
    void setDate(int day, int month, int year);
    void setDateAndTime(int day, int month, int year,
                               int hour, int minute, int second);
    LocalDateTime getLocalDateTime();

    static ZoneId getZoneId (String zoneString) {
        try {
            return ZoneId.of(zoneString);
        } catch (DateTimeException e) {
            System.err.println("Invalid time zone: " + zoneString +
                "; using default time zone instead.");
            return ZoneId.systemDefault();
        }
    }

    default ZonedDateTime getZonedDateTime(String zoneString) {
        return ZonedDateTime.of(getLocalDateTime(), getZoneId(zoneString));
    }
}

Verwenden Sie die folgenden Richtlinien, um auszuwählen, ob eine Schnittstelle oder eine abstrakte Klasse verwendet werden soll.

Schnittstelle:

  1. Um einen Vertrag zu definieren (vorzugsweise staatenlos - ich meine keine Variablen)
  2. Das Verknüpfen von nicht verwandten Klassen mit verfügt über Funktionen.
  3. Öffentliche konstante Variablen deklarieren ( unveränderlicher Zustand )

Abstrakte Klasse:

  1. Teilen Sie den Code zwischen mehreren eng verwandten Klassen. Es stellt eine Beziehung her.

  2. 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.


Was meinst du mit "staatenlosem Vertrag"? Es ist Punkt 1 über Schnittstellen
Maksim Dmitriev

1
Fehlen eines veränderlichen Zustands. Da die Schnittstelle Konstanten haben kann, können Daten im Gegensatz zu abstrakten Klassen mutiert werden
Ravindra babu

1
Korrektur in obiger Aussage. In der Schnittstelle können Daten im Gegensatz zur abstrakten Klasse nicht mutiert werden
Ravindra babu

2
Das ist die beste Antwort. Es befasst sich nicht nur mit Java8, sondern erklärt auch, in welchen bestimmten Situationen Sie eine der beiden Situationen verwenden würden.
Shuklaswag

Das Konzept der statelessIn-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).
Kaihua

22

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


1
Link geteilt wird ist wirklich genial
Premraj

Sie können die Standardimplementierung in Java-Schnittstellen mit dem Standardschlüsselwort
Ogen

21

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

  1. Eine Schnittstelle definiert einen Vertrag , den eine Implementierung für Sie erfüllen wird .

  2. 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

  1. Eine Schnittstelle dient zum Definieren öffentlicher APIs
  2. Eine abstrakte Klasse ist für den internen Gebrauch und zum Definieren von SPIs vorgesehen

Zum Beispiel

Anders ausgedrückt: Eine konkrete Klasse erledigt die eigentliche Arbeit auf ganz bestimmte Weise. BeispielsweiseArrayList 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 aLinkedListverwendet 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 ListSchnittstelle nicht verfügbar gemacht , sondern nur eine konkrete ListKlasse, die LinkedListgenau 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 implementieren ArrayListSie 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 umzuschaltenListKlasse 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 AbstractCollectionbietet grundlegende Implementierungen für isEmptybasierend auf der Größe 0 ist, containsals Iterierte und vergleichen, addAllwie wiederholt add, 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 exceptionStubs 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:

Was ist besser für eine Abschlussballnacht, ein Auto oder ein Hotelzimmer zu mieten?

Die technische Antwort klingt wie folgt:

Nun, in einem Auto können Sie es früher tun, aber in einem Hotelzimmer können Sie es bequemer tun. Auf der anderen Seite befindet sich das Hotelzimmer nur an einem Ort, während Sie es im Auto an mehreren Orten tun können. Nehmen wir an, Sie können zum Aussichtspunkt gehen, um eine schöne Aussicht zu genießen, oder in einem Autokino. oder an vielen anderen Orten oder sogar an mehr als einem Ort. Das Hotelzimmer hat auch eine Dusche.

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".


Meinten Sie "Low-Coupling"?
user2418306

@ user2418306 Nein, Kohäsion ist ein allgemeinerer Begriff, der Kopplung einschließt, obwohl es sich um enge Synonyme handelt und jeder Begriff funktioniert hätte.
Sergiu Dumitriu

9

Was ist mit folgendem Denken:

  • Eine Beziehung zwischen einer Klasse und einer abstrakten Klasse ist vom Typ "is-a".
  • Eine Beziehung zwischen einer Klasse und einer Schnittstelle ist vom Typ "has-a".

Wenn Sie also eine abstrakte Klasse Säugetiere, eine Unterklasse Mensch und eine Schnittstelle Fahren haben, können Sie sagen

  • Jeder Mensch ist ein Säugetier
  • Jeder Mensch hat ein Fahren (Verhalten)

Mein Vorschlag ist, dass der Buchwissenssatz anzeigt, dass er den semantischen Unterschied zwischen beiden hören wollte (wie andere hier bereits vorgeschlagen).


9

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.

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 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:

public abstract class World...

    public Playable owner;

    public Playable getOwner() {
        return owner;
    }

    public void setOwner(Playable owner) {
        this.owner = owner;
    }

6

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?

  1. Wenn der Benutzer gemeinsame Funktionen für alle Objekte schreiben möchte.
  2. Abstrakte Klassen sind die beste Wahl für die zukünftige Neuimplementierung, um mehr Funktionen hinzuzufügen, ohne den Endbenutzer zu beeinträchtigen.

Warum Schnittstellen?

  1. Wenn der Benutzer unterschiedliche Funktionen schreiben möchte, sind dies unterschiedliche Funktionen für Objekte.
  2. Schnittstellen sind die beste Wahl, wenn die Anforderungen nach Veröffentlichung der Schnittstelle nicht geändert werden müssen.

5

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.


4

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.


1
Können Sie mir sagen, wie Sie darauf geantwortet haben? Vielleicht kann es mir helfen.
Code_fish

Wenn Sie die Antwort erhalten, bietet dies viel weniger, als Ihnen bei der Ausarbeitung zu helfen. Geben Sie im Grunde ein praktisches Beispiel dafür, wann Sie die einzelnen Aufgaben verwenden würden, und erklären Sie, warum die einzelnen Aufgaben für die verschiedenen Aufgaben geeignet sind.
Adrian

4

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 wie calculateRPM(). Es ist eine übliche Methode, und Sie lassen den Kunden sein eigenes Verhalten wie
calculateMaxSpeed()usw. implementieren . Wahrscheinlich hätten Sie dies anhand einiger Echtzeitbeispiele erklärt, auf die Sie in Ihrer täglichen Arbeit gestoßen sind.



3

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.


3

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.


2

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.


2

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?

  1. Sie identifizieren Ihre Anforderungen und schließen einen Vertrag mit diesen Anforderungen.
  2. Rufen Sie dann die Ausschreibungen auf, um Ihr Projekt zu erstellen
  3. Wer auch immer das Projekt baut, das sollte Ihren Anforderungen entsprechen. Die Konstruktionslogik unterscheidet sich jedoch von Anbieter zu Anbieter.

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.


2

In wenigen Worten würde ich folgendermaßen antworten:

  • Vererbung über Klassenhierarchie impliziert eine Zustandsvererbung ;
  • in der Erwägung, dass Vererbung über Schnittstellen für Verhaltensvererbung steht ;

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.


1

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.


1

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.


1

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):

"Die Auswahl einer abstrakten Klasse gegenüber einer Schnittstellenklasse hängt davon ab, wie die Zukunft des Codes aussehen wird.

Abstrakte Klassen ermöglichen eine bessere Vorwärtskompatibilität, da Sie einer abstrakten Klasse auch in Zukunft Verhalten hinzufügen können, ohne Ihren vorhandenen Code zu beschädigen -> dies ist mit einer Schnittstellenklasse nicht möglich.

Andererseits sind Schnittstellenklassen flexibler als abstrakte Klassen. Dies liegt daran, dass sie mehrere Schnittstellen implementieren können . Die Sache ist, dass Java keine Mehrfachvererbungen hat, sodass Sie bei Verwendung abstrakter Klassen keine andere Klassenhierarchiestruktur verwenden können ...

Am Ende lautet eine gute allgemeine Faustregel: Verwenden Sie lieber Schnittstellenklassen, wenn in Ihrer Codebasis keine / Standardimplementierungen vorhanden sind. Verwenden Sie abstrakte Klassen, um die Kompatibilität zu gewährleisten, wenn Sie wissen, dass Sie Ihre Klasse in Zukunft aktualisieren werden. "

Viel Glück bei deinem nächsten Interview!


1

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.

Jetzt können Sie fragen, was wäre, wenn Runnable eine abstrakte Klasse wäre?

Nun, technisch war das möglich, aber in Bezug auf das Design wäre dies ein schlechter Grund gewesen:

  • Runnable ist kein Status zugeordnet und bietet auch keine Standardimplementierung für die run () -Methode
  • Die Aufgabe müsste es erweitern, damit es keine andere Klasse erweitern kann
  • Die Aufgabe hat als Spezialisierung für die Runnable-Klasse nichts zu bieten. Sie muss lediglich die run () -Methode überschreiben

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.

Setzen Sie uns einfach eine Schnittstelle, um eine Fähigkeit (einen Vertrag) zu definieren, und verwenden Sie eine abstrakte Klasse, um die Skelettimplementierung (allgemein / teilweise) zu definieren.

Haftungsausschluss: Dummes Beispiel folgt, versuchen Sie nicht zu beurteilen :-P

interface Forgiver {
    void forgive();
}

abstract class GodLike implements Forgiver {
    abstract void forget();
    final void forgive() {
        forget();
    }
}

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:

class HumanLike implements Forgiver {
    void forgive() {
       // forgive but remember    
    }
}

Oder Sie entscheiden sich dafür, gottähnlich zu sein und Folgendes zu tun:

class AngelLike extends GodLike {
    void forget() {
       // forget to forgive     
    }
}

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.


1

Fast alles scheint hier bereits behandelt zu sein. Noch ein Punkt zur praktischen Umsetzung des abstractUnterrichts:

abstractDas Schlüsselwort wird auch verwendet, um zu verhindern, dass eine Klasse instanziiert wird. Wenn Sie eine konkrete Klasse haben, die Sie nicht instanziieren möchten - machen Sie es abstract.


1

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.

public abstract class CTC {

    public int salary(int hra, int da, int extra)
    {
        int total;
        total = hra+da+extra;
        //incentive for specific performing employee
        //total = hra+da+extra+incentive;
        return total;
    }
}

class Manger extends CTC
{
}


class CEO extends CTC
{
}

class Developer extends CTC
{   
}

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.

public interface EmployeType {

    public String typeOfEmployee();
}

class ContarctOne implements EmployeType
{

    @Override
    public String typeOfEmployee() {
        return "contract";
    }

}

class PermanentOne implements EmployeType
{

    @Override
    public String typeOfEmployee() {
        return "permanent";
    }

}

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.


1

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.


0

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.


0

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.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.