it-swarm.com.de

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

In einem meiner Interviews wurde ich gebeten, den Unterschied zwischen einem Interface und einem Abstract class zu erklären.

Hier ist meine Antwort:

Methoden einer Java -Schnittstelle sind implizit abstrakt und können nicht implementiert werden. Eine Java abstrakte 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 Java abstrakte Klasse kann die üblichen Varianten von Klassenmitgliedern wie privat, geschützt usw. haben.

Eine Java -Schnittstelle sollte mit dem Schlüsselwort "implements" implementiert werden. Eine Java abstrakte Klasse sollte mit dem Schlüsselwort "extend" 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 Klasse Java kann mehrere Schnittstellen implementieren, aber nur 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 und erklärte , wann ich eine abstrakte Klasse über eine Schnittstelle wählen würde, unter Verwendung praktischer Beispiele .

Was habe ich falsch gemacht?

448
Thinker

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 obigen 2 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 () nicht datenbankabhängig ist und für jede Klasse gleich ist? Dann wäre das Obige 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 Methode, die datenbankabhängig ist.

Ich habe mein Bestes versucht und hoffe, dies wird Ihre Zweifel klären.

488
Vimal Bera

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 Dokument für das Verständnis zwischen verschiedenen Teams in der Softwareentwicklung fungieren.

  2. Schnittstellen geben die Idee, was zu tun ist, aber nicht, wie es getan wird. 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 unverändert verwenden oder ignorieren, indem Sie sie überschreiben und ihre eigene Implementierung zuweisen).

  5. Darüber hinaus werden die Methoden mit derselben Signatur, die das Verhalten in verschiedenen Kontexten ändern können, als Schnittstellendeklarationen als Regeln bereitgestellt, um sie in verschiedenen Kontexten entsprechend zu implementieren.

Edit: Java 8 erleichtert das Definieren von Standardmethoden 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, eine 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);
    }

}

In Java ist es nicht möglich, mehrere Klassen zu erweitern, da dies zum "Diamond-Problem" führt, bei dem der Compiler nicht entscheiden kann, welche Methode der Superklasse verwendet werden soll. Bei den Standardmethoden tritt das Diamantproblem auch bei Schnittstellen auf. Denn wenn eine Klasse beide implementiert

SomeInterfaceOne and SomeInterfaceTwo

wenn die allgemeine Standardmethode nicht implementiert wird, kann der Compiler nicht entscheiden, welche Methode ausgewählt werden soll. Um dieses Problem zu vermeiden, ist es in Java 8 obligatorisch, gemeinsame Standardmethoden für verschiedene Schnittstellen zu implementieren. Wenn eine Klasse beide oben genannten Schnittstellen implementiert, muss sie die Implementierung für die defaultMethod () -Methode bereitstellen, da der Compiler sonst einen Fehler bei der Kompilierung auslöst.

192
Shailesh Saxena

Sie haben die praktischen Unterschiede in der 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 und nicht wiederholt erstellt werden müssen. Unterklassen müssen das Verhalten vervollständigen und die Option haben, vordefiniertes Verhalten zu überschreiben (solange es nicht als final oder private definiert ist).

Sie finden gute Beispiele 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 grundlegende Implementierung 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.

156
Daniel Lerps

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 zu tun ist ​​.

Dieses Konzept kann am Beispiel besser verstanden werden:

Betrachten Sie eine Zahlungsklasse. Die Zahlung kann auf verschiedene Arten erfolgen, z. B. über Paypal, Kreditkarte usw. Normalerweise verwenden wir also Payment 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, für die wir wissen, wie sie auszuführen sind.

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 gegebenen abstrakten Klasse in Zukunft Methoden (konkret/abstrakt) hinzufügen, muss der Code der Implementierungsklasse nicht geändert werden. Wenn wir jedoch in Zukunft Methoden in eine Schnittstelle einfügen, müssen wir allen Klassen, die diese Schnittstelle implementiert haben, Implementierungen hinzufügen. Andernfalls treten Fehler bei der Kompilierung auf.

Es gibt noch andere Unterschiede, aber es handelt sich hierbei möglicherweise um größere, die von Ihrem Interviewer erwartet wurden. Hoffentlich war das hilfreich.

84
Satya

Unterschied zwischen Abstact-Klasse und Schnittstelle

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

Standardmethoden für die Benutzeroberfläche in Java 8

  1. Was ist die Standardmethode?
  2. Kompilierungsfehler für jede Methode, der mit der Standardmethode behoben wurde
  3. Probleme mit der Standardmethode und der 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 Java interface:

Java-Funktionsschnittstellen



Abstrakte Klassen versus Schnittstellen in Java 8

Java 8-Schnittstellenänderungen umfassen statische Methoden und Standardmethoden in Schnittstellen. Vor Java 8 konnten wir nur Methodendeklarationen in den Interfaces haben. Ab Java 8 können wir jedoch Standardmethoden und statische Methoden in den Schnittstellen haben.

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 einen damit verbundenen Zustand haben. Im Gegensatz dazu kann die Standardmethode nur implementiert werden, indem andere Schnittstellenmethoden aufgerufen werden, ohne dass auf den Status einer bestimmten Implementierung verwiesen wird. Daher hängt sowohl die Verwendung für unterschiedliche Zwecke als auch die Auswahl zwischen zwei wirklich vom Szenariokontext ab.

Konzeptueller Unterschied:

Abstrakte Klassen sind für skelettartige (d. H. Teilweise) Implementierungen von Schnittstellen gültig, sollten jedoch nicht ohne eine passende Schnittstelle existieren.

Können Standardmethoden dies auch beseitigen, wenn abstrakte Klassen effektiv auf geringe Sichtbarkeit reduziert werden? Beschlossen: Nein! Für die Implementierung von Schnittstellen sind fast immer einige oder alle Tools zur Klassenerstellung erforderlich, denen 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 für die Benutzeroberfläche in Java 8

Java 8 führt die neue Funktion " Standardmethode " oder "Defender-Methode" ein, mit der Entwickler den Schnittstellen neue Methoden hinzufügen können, ohne die vorhandene Implementierung dieser Schnittstelle zu beeinträchtigen. Sie bietet Flexibilität, damit die Schnittstelle eine Implementierung definieren kann, die als Standard 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 Möglichkeit, kurze und wiederverwendbare Methoden zu schreiben, stark einschränkt.

Standardmethoden können einer Schnittstelle bereitgestellt werden, ohne dass dies Auswirkungen auf die Implementierung von Klassen hat, da sie eine Implementierung enthält. Wenn jede hinzugefügte Methode in einem Interface mit Implementierung definiert ist, ist keine implementierende Klasse betroffen. 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 beeinträchtigen.

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

  1. Überschreiben Sie die Standardmethode nicht und übernehmen Sie die Standardmethode.
  2. Überschreiben Sie die Standardmethode, ähnlich wie bei anderen Methoden, die wir in der Unterklasse überschreiben.
  3. Standardmethode als abstrakt neu deklarieren, wodurch die Unterklasse gezwungen wird, sie zu überschreiben.

Kompilierungsfehler für jede Methode, der mit der Standardmethode behoben wurde

Für Java 8 wurden die JDK-Sammlungen erweitert und forEach-Methoden zur gesamten Sammlung hinzugefügt (die in Verbindung mit Lambdas funktionieren). 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 daher eine Standardmethode mit einer erforderlichen Implementierung hinzugefügt, damit die vorhandene Implementierung nicht geändert wird.

Die Iterable-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 die JDK-Schnittstelle einzufügen, ohne die implementierenden Klassen zu unterbrechen.


Probleme mit der Standardmethode und der Mehrfachvererbung

Da Java Class mehrere Interfaces implementieren kann und jedes Interface 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: Klasse Impl erbt nicht verwandte Standardwerte für defaultMethod () von den Typen InterfaceA und InterfaceB

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

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

Wenn wir die Standardimplementierung aufrufen möchten, die von einem der Super-Interfaces 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();
    }
}

Als Teil unserer neuen Methode können wir eine Standardimplementierung oder beides auswählen.

Wichtige Punkte zu den Standardmethoden der Java -Schnittstelle:

  1. Standardmethoden für Java-Schnittstellen helfen uns bei der Erweiterung von Schnittstellen, ohne befürchten zu müssen, Implementierungsklassen zu knacken.
  2. Mit den Standardmethoden für Java-Schnittstellen werden 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 Methoden der Collections-Klasse in den Schnittstellen selbst bereitgestellt werden.
  4. Die Standardmethoden der Java-Schnittstelle helfen uns beim Entfernen von Basisimplementierungsklassen. Wir können Standardimplementierungen bereitstellen und die Implementierungsklassen können auswählen, welche zu überschreiben sind.
  5. Einer der Hauptgründe für die Einführung von Standardmethoden in Interfaces ist die Verbesserung der Collections-API in Java 8, um Lambda-Ausdrücke zu unterstützen.
  6. Wenn eine Klasse in der Hierarchie über eine Methode mit derselben Signatur verfügt, sind Standardmethoden nicht mehr relevant. Eine Standardmethode kann eine Methode aus Java.lang.Object nicht überschreiben. Die Argumentation ist sehr einfach, da Object die Basisklasse für alle Klassen Java ist. Selbst wenn Objektklassenmethoden als Standardmethoden in Schnittstellen definiert sind, ist dies nutzlos, da die Objektklassenmethode immer verwendet wird. Aus diesem Grund können wir keine Standardmethoden verwenden, die Objektklassenmethoden überschreiben, um Verwirrung zu vermeiden.
  7. Die Standardmethoden der Java-Oberfläche werden auch als Defender-Methoden oder virtuelle Erweiterungsmethoden bezeichnet.

Ressourcen-Link:

  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, unerwünschte Ergebnisse zu vermeiden, die bei einer schlechten Implementierung in Implementierungsklassen auftreten können. 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;
    }
}

Sehen wir uns nun eine Implementierungsklasse an, die die isNull () -Methode mit einer schlechten 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 die Annotation @Override zur Methode isNull () hinzufügen, führt dies zu einem Compilerfehler.

Wenn wir jetzt 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 Java-Schnittstellenmethode ist nur für Schnittstellenmethoden sichtbar. Wenn Sie die isNull () -Methode aus der MyDataImpl-Klasse entfernen, können Sie sie nicht für das MyDataImpl-Objekt verwenden. Wie bei anderen statischen Methoden können wir auch bei statischen Methoden der Benutzeroberfläche Klassennamen verwenden. Eine gültige Anweisung lautet beispielsweise:

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

Wichtige Punkte zur statischen Methode Java interface:

  1. Die statische Methode der Java-Schnittstelle ist Teil der Schnittstelle. Sie kann nicht für Objekte der Implementierungsklasse verwendet werden.
  2. Statische Methoden der Java-Schnittstelle eignen sich zum Bereitstellen von Dienstprogrammmethoden, z. B. Nullprüfung, Sammlungssortierung usw.
  3. Die statische Methode der Java-Schnittstelle hilft uns bei der Bereitstellung von Sicherheit, indem sie verhindert, dass Implementierungsklassen sie überschreiben.
  4. Wir können keine statische Methode für die Schnittstelle für Objektklassenmethoden definieren. Es wird ein Compilerfehler angezeigt, da diese statische Methode die Instanzmethode nicht vor Object verbergen kann. Dies liegt daran, dass dies in Java nicht zulässig ist, da Object die Basisklasse für alle Klassen ist und es keine statische Methode auf Klassenebene und keine andere Instanzmethode mit derselben Signatur geben kann.
  5. Wir können statische Methoden der Java -Schnittstelle verwenden, um Dienstprogrammklassen wie Sammlungen zu entfernen und alle statischen Methoden in 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 Functional Interface bezeichnet.

Eine neue Annotation @FunctionalInterface wurde eingeführt, um eine Schnittstelle als funktionale Schnittstelle zu kennzeichnen. @FunctionalInterface Annotation ist eine Funktion, mit der das versehentliche Hinzufügen abstrakter Methoden zu den funktionalen Schnittstellen verhindert wird. Es ist optional, aber eine gute Praxis, es zu verwenden.

Funktionale Interfaces werden von Java 8 lange erwartet und nachgefragt, da wir damit Lambda-Ausdrücke verwenden können, 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.

Ressourcenposition:

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

Alle Ihre Aussagen mit Ausnahme Ihrer ersten Aussage (nach der Version Java 8) sind gültig:

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 ähnlich ist 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 erneut, wodurch sie abstract wird.
  3. Definieren Sie die Standardmethode neu, die diese überschreibt.

Statische Methoden:

Zusätzlich zu 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 verwendet ihre statischen Methoden gemeinsam.)

Dies erleichtert Ihnen das Organisieren von Hilfsmethoden in Ihren Bibliotheken.

Beispielcode von der Dokumentationsseite über interface mit static und default Methoden.

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 Sie eine Schnittstelle oder eine abstrakte Klasse verwenden möchten.

Schnittstelle:

  1. Um einen Vertrag zu definieren (vorzugsweise zustandslos - ich meine keine Variablen)
  2. Das Verknüpfen von nicht verwandten Klassen mit hat die Fähigkeit .
  3. Öffentliche konstante Variablen deklarieren ( unveränderlicher Zustand )

Abstrakte Klasse:

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

  2. Gemeinsamen Status unter verwandten Klassen teilen (Status kann in konkreten Klassen geändert werden)

Zusammenhängende Posts:

Schnittstelle gegen abstrakte Klasse (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.

39
Ravindra babu

Ihre Erklärung sieht anständig aus, aber könnte es sein, dass Sie alles aus einem Lehrbuch gelesen haben? : - /

Was mich mehr stört, ist, wie solide war Ihr Beispiel? Haben Sie sich die Mühe gemacht, fast alle Unterschiede zwischen abstrakt und Schnittstellen aufzunehmen ?

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

für eine vollständige Liste der Unterschiede ..

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

21
VictorCreator

Viele Nachwuchsentwickler machen den Fehler, Schnittstellen, abstrakte und konkrete Klassen als geringfügige Variationen derselben Sache zu betrachten, und wählen aus rein technischen Gründen eine aus: 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 ist das Hauptproblem verborgen: "I". 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 völlig unterschiedliche Bedeutungen und Zwecke, obwohl sie aus technischer Sicht offensichtlich ähnlich sind.

Zusammenfassung

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

  2. Eine abstrakte Klasse liefert ein Standardverhalten die Ihre Implementierung wiederverwenden kann.

Diese beiden obigen Punkte sind das, wonach ich beim Vorstellungsgespräch suche, und sie sind eine ausreichend kompakte Zusammenfassung. Lesen Sie weiter für weitere Details.

Alternative Zusammenfassung

  1. Eine Schnittstelle dient zum Definieren öffentlicher APIs
  2. Eine abstrakte Klasse dient zur internen Verwendung und zum Definieren von SPIs

Zum Beispiel

Anders ausgedrückt: Eine konkrete Klasse erledigt die eigentliche Arbeit auf ganz bestimmte Weise. Beispielsweise verwendet ein ArrayList einen zusammenhängenden Speicherbereich, um eine Liste von Objekten auf kompakte Weise zu speichern. Dies bietet schnellen wahlfreien Zugriff, Iteration und direkte Änderungen, ist jedoch bei Einfügungen, Löschungen und gelegentlich sogar schrecklich Ergänzungen; Ein LinkedList 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 beim wahllosen Zugriff furchtbar ist. Diese beiden Arten von Listen sind für unterschiedliche Anwendungsfälle optimiert, und es ist sehr wichtig, wie Sie sie verwenden. Wenn Sie versuchen, die Leistung aus einer Liste herauszuholen, mit der Sie intensiv interagieren, und wenn Sie die Art der Liste bestimmen, sollten Sie sorgfältig auswählen, welche Sie instanziieren.

Andererseits ist es Benutzern auf hoher Ebene einer Liste egal, wie sie tatsächlich implementiert wird, und sie sollten von diesen Details isoliert sein. Stellen wir uns vor, dass Java die List -Schnittstelle nicht verfügbar gemacht hat, sondern nur eine konkrete List -Klasse hat, die genau das ist, was LinkedList gerade ist. Alle Java - Entwickler hätten ihren Code an die Implementierungsdetails angepasst: Vermeiden Sie zufälligen Zugriff, fügen Sie einen Cache hinzu, um den Zugriff zu beschleunigen, oder implementieren Sie ArrayList einfach neu, obwohl dies nicht mit allen kompatibel wäre anderer Code, der tatsächlich nur mit List funktioniert. 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, für ihre einzige Klasse List auf eine Array-Liste umzuschalten verfügbar. Dies würde die Leistung jedes Java Programms auf der Welt beeinträchtigen, und die Leute wären darüber nicht glücklich. 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, ohne all die Eingeweide aufzudecken, die Programmierer dazu verleiten würden, ihren Code an die internen Details anzupassen, die sich bei zukünftigen Aktualisierungen ändern könnten .

Eine abstrakte Klasse befindet sich in der Mitte zwischen Interfaces und konkreten Klassen. Es soll Implementierungen dabei helfen, gemeinsamen oder langweiligen Code zu verwenden. Beispielsweise bietet AbstractCollection grundlegende Implementierungen für isEmpty basierend auf der Größe 0, contains als Iteration und Vergleich, addAll als Wiederholung add und so weiter. So können sich die Implementierungen auf die entscheidenden Teile konzentrieren, die sie voneinander unterscheiden: das Speichern und Abrufen von Daten.

Eine andere Perspektive: APIs versus SPIs

Schnittstellen sind kohäsionsarm Gateways zwischen verschiedenen Codeteilen. Sie ermöglichen es Bibliotheken zu existieren und sich zu entwickeln, ohne jeden Bibliotheksbenutzer zu unterbrechen, wenn sich intern etwas ändert. Es heißt Application Programming Interface, nicht Application Programming Classes. In kleinerem Maßstab ermöglichen sie auch mehreren Entwicklern die erfolgreiche Zusammenarbeit in großen Projekten, indem sie verschiedene Module durch gut dokumentierte Schnittstellen trennen.

Abstrakte Klassen haben eine hohe Kohäsion Helfer, die bei der Implementierung einer Schnittstelle verwendet werden sollen, vorausgesetzt, dass ein gewisser Grad an Implementierungsdetails vorliegt. 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 auf who ses und bei einem SPI liegt der Fokus auf who implementiert it.

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 zur Definition eines SPI Schnittstellen verwendet werden, muss ein Anbieter bei jeder Änderung des Vertrags SPI eine neue Version freigeben. 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 in Java 8 Standardmethoden für Schnittstellen eingeführt wurden, wodurch die Grenze zwischen Schnittstellen und abstrakten Klassen noch unschärfer wird, können Implementierungen den Code nicht wiederverwenden, sondern erleichtern das Ändern von Schnittstellen, die beide als API dienen und als SPI (oder werden fälschlicherweise zum Definieren von SPIs anstelle von abstrakten Klassen verwendet).

"Buchwissen"

Die technischen Details in der Antwort des OP gelten als "Buchwissen", da dies normalerweise der in der Schule und in den meisten Technologiebüchern verwendete Ansatz zu einer Sprache ist: was eine Sache ist, nicht wie) um es in der Praxis zu verwenden, insbesondere in großen Anwendungen.

Hier ist eine Analogie: Vermutlich lautete die Frage:

Was ist besser für einen Abschlussball, ein Auto oder ein Hotelzimmer zu mieten?

Die technische Antwort klingt wie folgt:

Nun, in einem Auto kann man es früher machen, aber in einem Hotelzimmer kann man es bequemer machen. Auf der anderen Seite befindet sich das Hotelzimmer nur an einem Ort, während Sie es im Auto an mehreren Orten erledigen können. Nehmen wir an, Sie können zum Vista-Punkt 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 geht völlig daneben, dass es sich um zwei völlig verschiedene Dinge handelt und beide gleichzeitig für unterschiedliche Zwecke verwendet werden können, und der Aspekt "es zu tun" ist bei keiner der beiden Optionen das Wichtigste . Der Antwort fehlt die Perspektive, sie zeigt eine unausgereifte Denkweise, während sie die wahren "Tatsachen" korrekt darstellt.

20
Sergiu Dumitriu

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 die Aktualisierung eines Spiels von 2D auf 3D. 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 diese Methoden dennoch von einem Objekt 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 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;
    }
9

Was ist mit folgender Denkweise:

  • 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, dann können Sie sagen

  • jeder Mensch ist ein Säugetier
  • jeder Mensch hat ein Fahrverhalten

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

9
akohout

Abstrakte Klassen sind keine reine Abstraktion, sondern eine Sammlung konkreter (implementierter) und nicht implementierter Methoden. Aber Schnittstellen sind reine Abstraktion. Es gibt nur unimplementierte Methoden, keine konkreten Methoden.

Warum abstrakte Klassen?

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

Warum Schnittstellen?

  1. Wenn Benutzer unterschiedliche Funktionen schreiben möchten, sind dies unterschiedliche Funktionen für Objekte.
  2. Schnittstellen sind die beste Wahl, wenn die Anforderungen nicht geändert werden müssen, nachdem die Schnittstelle veröffentlicht wurde.
6
Sarfaraz Ahamad

Eine Schnittstelle ist wie eine Reihe von Genen, deren Wirkung öffentlich dokumentiert ist: Ein DNA-Test sagt mir, ob ich sie habe - und wenn ich das tue, kann ich öffentlich bekannt machen, dass ich ein "Träger" bin und ein Teil meines Verhaltens oder Zustands ihnen entsprechen wird. (Aber natürlich habe ich möglicherweise viele andere Gene, die Merkmale bieten, die außerhalb dieses Bereichs liegen.)

Eine abstrakte Klasse ist wie die tote Vorfahrin einer gleichgeschlechtlichen Spezies (*): Sie kann nicht dazu gebracht werden Das Leben aber ein lebender (dh nicht abstrakter ) Nachkomme erbt alle ihre Gene.

(*) Um diese Metapher zu erweitern, nehmen wir an, dass alle Mitglieder der Spezies dasselbe Alter haben. Das heißt, alle Vorfahren eines toten Vorfahren müssen ebenfalls tot sein - und ebenso müssen alle Nachkommen eines lebenden Vorfahren am Leben sein.

5
Steve Chambers

Ich mache Interviews für die Arbeit und ich würde Ihre Antwort auch ungünstig sehen (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 noch nie in der Praxis verwendet.

Eine gute Erklärung, warum Sie beide verwenden, kann weitaus besser sein als eine genaue Erklärung des Unterschieds. Die Arbeitgeber möchten, dass die Programmierer Dinge tun, die sie nicht kennen, was sich in einem Interview nur schwer demonstrieren lässt. Die Antwort, die Sie gaben, wäre gut, wenn Sie sich für einen technischen oder dokumentationsbasierten Job bewerben würden, aber nicht als Entwickler.

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 sollten Sie darüber nachdenken. https://workplace.stackexchange.com/ kann ein ausgezeichneter Ort für solche Dinge sein.

4
Adrian

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 zu sehen.

3
user2822053

Der Hauptunterschied, den ich beobachtet habe, war, dass die abstrakte Klasse uns einige bereits implementierte allgemeine Verhaltensweisen bietet und Unterklassen nur spezifische Funktionen implementieren müssen, die ihnen entsprechen. Wobei für eine Schnittstelle nur spezifiziert wird, welche Aufgaben zu erledigen sind, und von der Schnittstelle keine Implementierungen angegeben werden. Ich kann sagen, es spezifiziert den Vertrag zwischen sich selbst und implementierten Klassen.

3
user2729112

Sogar ich habe mich in mehreren Interviews der gleichen Frage gestellt und glaube mir, es macht deine Zeit miserabel, den Interviewer zu überzeugen. Wenn mir alle Antworten von oben inhärent sind, muss ich noch einen wichtigen Punkt hinzufügen, damit es überzeugender ist und OO von seiner besten Seite ist

Für den Fall, dass Sie nicht sind planung von Änderungen in den Regeln Wenn die Unterklasse für eine lange Zukunft befolgt werden soll, wählen Sie die Schnittstelle, da Sie sie nicht ändern können, und wenn Sie dies tun, müssen Sie die Änderungen für alle anderen Unterklassen vornehmen du denkst, sie möchten die Funktionalität wiederverwenden, einige Regeln festlegen und sie auch für Änderungen öffnen, geh in die abstrakte Klasse.

Denken Sie auf diese Weise, Sie hätten einen Verbrauchsgüter-Service verwendet oder der Welt einen Code zur Verfügung gestellt, und Sie hätten die Möglichkeit, etwas zu ändern. Nehmen Sie eine Sicherheitsüberprüfung an Finde alle gelesenen Markierungen in meiner Eclipse, die gesamte Anwendung ist ausgefallen. Um solche Alpträume zu vermeiden, verwenden Sie Abstract over Interfaces

Ich denke, das könnte den Interviewer in gewissem Maße überzeugen ... Frohe Interviews voraus.

3
vinod bazari

Sie wählen Interface in Java, um das Diamond-Problem bei Mehrfachvererbung zu vermeiden.

Wenn Sie möchten, dass alle Ihre Methoden von Ihrem Client implementiert werden, entscheiden Sie sich für eine Schnittstelle. Dies bedeutet, dass Sie die gesamte Anwendung abstrakt gestalten.

Sie wählen die abstrakte Klasse, wenn Sie bereits wissen, was gemeinsam ist. Nehmen Sie zum Beispiel eine abstrakte Klasse Car. Auf einer höheren Ebene implementieren Sie die gängigen Automethoden wie calculateRPM(). Es ist eine gängige Methode und Sie lassen den Kunden sein eigenes Verhalten gerne umsetzen
calculateMaxSpeed() etc. Wahrscheinlich hätten Sie das anhand weniger Echtzeitbeispiele erklärt, die Sie in Ihrem täglichen Job erlebt haben.

3
MaheshVarma

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 übergeordnet ist.

Wenn ich versuche, einen Typ zu definieren, eine Liste von Methoden, die ein Benutzer meines Objekts zuverlässig aufrufen kann, dann erstelle ich eine Schnittstelle.

Zum Beispiel würde ich niemals eine abstrakte Klasse mit einer konkreten Unterklasse erstellen, da es bei 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 wird nicht wissen, dass es nur eine Implementierung gibt. Tatsächlich wird es in einer zukünftigen Version möglicherweise mehrere Implementierungen geben, die alle Unterklassen einer neuen abstrakten Klasse sind, die es bei der Erstellung der Schnittstelle noch nicht gab.

Das hätte vielleicht auch ein bisschen zu buchstäblich gewirkt (obwohl ich es noch nie so gesehen habe, wie 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.

Noch eine Sache. Java 8 ermöglicht es Ihnen jetzt, Standardcode in eine Schnittstelle einzufügen, wodurch die Grenze zwischen Schnittstellen und abstrakten Klassen weiter verwischt wird. Aber nach allem, was ich gesehen habe, wird dieses Feature sogar von den Machern der Java Kernbibliotheken überbeansprucht. Diese Funktion wurde zu Recht hinzugefügt, um die Erweiterung einer Schnittstelle zu ermöglichen, ohne dass es zu einer binären Inkompatibilität kommt. 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
Teto

Der grundlegende Unterschied zwischen der Schnittstelle und der abstrakten Klasse besteht darin, dass die Schnittstelle Mehrfachvererbung unterstützt, die abstrakte Klasse jedoch nicht.

In abstract class können Sie auch alle abstrakten Methoden wie interface 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 fragen den Benutzer, der diese Klasse erweitert, bitte geben Sie Ihre Absicht in der abstrakten Methode an. 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 erstellt, der sollte Ihre Anforderungen erfüllen. Die Konstruktionslogik unterscheidet sich jedoch von Hersteller zu Hersteller.

Hier kümmere ich mich nicht um die Logik, wie sie aufgebaut sind. Das endgültige Objekt hat meine Anforderungen erfüllt oder nicht, dass nur mein entscheidender Punkt.

Hier werden Ihre Anforderungen als Schnittstelle und Konstruktoren als Implementierer bezeichnet.

2
Dharisi Suresh

Ich werde versuchen, anhand eines praktischen Szenarios zu antworten, um den Unterschied zwischen den beiden aufzuzeigen.

Schnittstellen kommen mit einer Nutzlast von Null, d. H., Es muss kein Zustand aufrechterhalten werden, und daher ist es die bessere Wahl, einen Vertrag (eine Fähigkeit) nur einer Klasse zuzuordnen.

Angenommen, ich habe eine Task-Klasse, die eine Aktion ausführt. Um jetzt eine Task in einem separaten Thread auszuführen, muss ich die Thread-Klasse nicht wirklich erweitern. Eine bessere Wahl ist, die Task-Schnittstelle Runnable 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 die Methode start () auf.

Nun können Sie sich fragen, ob Runnable eine abstrakte Klasse war.

Nun, technisch war das möglich, aber in Bezug auf das Design wäre dies ein Grund für die schlechte Wahl gewesen:

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

Mit anderen Worten, die Task-Klasse benötigte eine Fähigkeit, in einem Thread ausgeführt zu werden, die durch die Implementierung von Runnable-Interface-Versen erreicht wurde, die die Thread-Klasse erweitern, die sie zu einem Thread machen würden.

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

Disclaimer: dummes Beispiel folgt, versuche nicht zu urteilen :-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 auch dafür entscheiden, nur verzeihend zu sein (d. H. Nicht gottähnlich) und Folgendes tun:

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

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

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

P.S. mit Java 8-Schnittstelle kann auch statische als auch standardmäßige (überschreibbare Implementierungs-) Methoden haben, und daher wird der Unterschied zwischen S/W-Schnittstelle und abstrakter Klasse noch weiter eingegrenzt.

1
sactiw

Ja, Ihre Antworten waren technisch korrekt, aber wo Sie falsch liefen, haben Sie nicht gezeigt, dass Sie die Vor- und Nachteile einer Auswahl vor der anderen verstehen. Darüber hinaus waren sie wahrscheinlich besorgt ü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 Interface - Klasse hängt davon ab, wie wir die Zukunft des Codes projizieren.

Abstrakte Klassen ermöglichen eine bessere Aufwärtskompatibilität, da Sie einer abstrakten Klasse auch in Zukunft Verhalten hinzufügen können, ohne den 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 von abstrakten Klassen keine andere Klassenhierarchiestruktur verwenden können ...

Am Ende lautet die Faustregel also: Verwenden Sie lieber Schnittstellenklassen, wenn Ihre Codebasis keine vorhandenen/Standardimplementierungen enthält. 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 beim nächsten Interview!

1
Jaxian

hmm, jetzt sind die Leute hungrig, praktisch, Sie haben völlig recht, aber die meisten Interviewer sehen nach ihren aktuellen Anforderungen aus und wollen einen praktischen Ansatz.

nach Beendigung Ihrer Antwort sollten Sie auf das Beispiel springen:

Abstract:

zum Beispiel haben wir eine Gehaltsfunktion, die allen Mitarbeitern gemeinsam ist. Dann können wir eine abstrakte Klasse namens CTC mit einem teilweise definierten Methodenkörper haben, die von jedem Mitarbeitertyp erweitert wird und entsprechend ihrer zusätzlichen Stärken 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 Schnittstelle in Java ermöglicht die Verwendung der Schnittstellenfunktionalität, ohne diese zu erweitern, und Sie müssen sich mit der Implementierung der Signatur der Funktionalität, die Sie in Ihre Anwendung einführen möchten, klar sein. es wird dich zwingen, definiton zu haben. Für verschiedene 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 einer abstrakten Klasse haben, indem Sie Methoden als eine abstrakte definieren. Jetzt erweitert eine Klasse die abstrakte Klasse als eine abstrakte, bis sie diese abstrakte Funktion überschreibt.

1
RTA

Fast alles scheint hier bereits behandelt zu sein. Noch ein Punkt zur praktischen Umsetzung der Klasse abstract:

Das Schlüsselwort abstract 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 sie abstract.

1
Blade

Nach dem, was ich verstehe und wie ich vorgehe,

Interface ist wie eine Spezifikation/ein Vertrag. Jede Klasse, die eine Interface-Klasse implementiert, muss alle in der abstrakten Klasse definierten Methoden implementieren (mit Ausnahme der Standardmethoden (eingeführt in Java 8).

Während ich eine Klassenzusammenfassung definiere, wenn ich die für einige Methoden der Klasse erforderliche Implementierung und einige Methoden weiß, 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 in der Entwicklung, wenn ich weiß, wie diese Methoden implementiert werden sollen, diese abstrakte Klasse einfach erweitern und diese Methoden implementieren kann.

Hinweis: Sie können in Schnittstellenmethoden keinen Funktionsrumpf verwenden, es sei denn, die Methode ist statisch oder standardmäßig.

1
Akash Lodha

In der abstrakten Klasse können Sie die Standardimplementierung von Methoden schreiben! Aber im Interface kannst du nicht. Grundsätzlich existieren in interface rein virtuelle Methoden, die von der Klasse implementiert werden müssen, die das Interface implementiert.

1
dg_no_9

Soweit ich weiß, wird eine Schnittstelle, die aus endgültigen Variablen und Methoden ohne Implementierungen 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 Superklasse 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
Marz

Ich glaube, was der Interviewer versucht hat, war wahrscheinlich der Unterschied zwischen Schnittstelle und Implementierung.

Die Schnittstelle - keine Java -Schnittstelle, sondern allgemein "Schnittstelle" - zu einem Codemodul ist im Grunde der Vertrag mit Clientcode, der die Schnittstelle verwendet.

Die Implementierung eines Codemoduls ist der interne Code, mit dem das Modul funktioniert. Häufig können Sie eine bestimmte Schnittstelle auf mehrere Arten implementieren und sogar die Implementierung ändern, ohne dass der Client-Code 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 zugunsten des Clientcodes mithilfe der Klasse verhält, ohne dass eine Implementierung angegeben wird. Daher enthält eine Schnittstelle Methodensignaturen - die Namen, Rückgabetypen und Argumentlisten - für Methoden, von denen erwartet wird, dass sie vom Client-Code aufgerufen werden. Grundsätzlich sollte jede Methode über genügend Javadoc verfügen, um die Funktionsweise dieser Methode zu beschreiben. Der überzeugendste Grund für die Verwendung einer Schnittstelle besteht darin, dass Sie mehrere verschiedene Implementierungen der Schnittstelle planen und abhängig von der Bereitstellungskonfiguration möglicherweise eine Implementierung auswählen.

Im Gegensatz dazu bietet eine abstrakte Klasse Java eine teilweise Implementierung der Klasse, anstatt in erster Linie 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 wird der gemeinsam genutzte Code nur an einer Stelle angezeigt - der abstrakten Klasse - und es wird klargestellt, dass Teile der Implementierung in der abstrakten Klasse nicht vorhanden sind und voraussichtlich von Unterklassen bereitgestellt werden.

0
Warren Dew

ihre Antwort ist richtig, aber der Interviewer möchte, dass Sie nach der Perspektive der Softwareentwicklung und nicht nach den Details von Java differenzieren.

Einfache Worte:

Ein Interface ist wie das Interface eines Shops. Alles, was darauf gezeigt wird, sollte im Shop vorhanden sein. Daher muss jede Methode im Interface in der konkreten Klasse implementiert sein. Was nun, wenn einige Klassen einige exakte Methoden teilen und in anderen variieren? Angenommen, das Interface handelt von einem Geschäft, das zwei Dinge enthält. Angenommen, wir haben zwei Geschäfte, die beide Sportausrüstung enthalten, aber einer hat Kleidung und der andere Schuhe. Sie erstellen also eine abstrakte Klasse für Sport, die die Sports-Methode 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.

0
Mosab Shaheen