1. Fähigkeiten

Um die Vorteile von Schnittstellen und deren Verwendung besser zu verstehen, müssen wir über einige abstraktere Dinge sprechen.

Eine Klasse modelliert normalerweise ein bestimmtes Objekt. Eine Schnittstelle entspricht weniger Objekten als vielmehr ihren Fähigkeiten oder Rollen.

Die Essenz von Schnittstellen

Dinge wie Autos, Fahrräder, Motorräder und Räder lassen sich beispielsweise am besten als Klassen und Objekte darstellen. Aber ihre Fähigkeiten – wie „Ich kann geritten werden“, „Ich kann Menschen transportieren“, „Ich kann stehen“ – lassen sich besser als Schnittstellen darstellen. Hier sind einige Beispiele:

Code Beschreibung
interface CanMove
{
   void move(String newLocation);
}
Entspricht der Fähigkeit, sich zu bewegen
interface Rideable
{
   void ride(Passenger passenger);
}
Entspricht der Reitfähigkeit
interface CanTransport
{
   void addStuff(Object stuff);
   Object removeStuff();
}
Entspricht der Fähigkeit, Dinge zu transportieren
class Wheel implements CanMove
{
   ...
}
Die WheelKlasse kann umziehen
class Car implements CanMove, Rideable, CanTransport
{
   ...
}
Die CarKlasse kann sich bewegen, reiten und Sachen transportieren
class Skateboard implements CanMove, Rideable
{
   ...
}
Die SkateboardKlasse kann sich bewegen und geritten werden


2. Rollen

Schnittstellen vereinfachen das Leben eines Programmierers erheblich. Sehr oft hat ein Programm Tausende von Objekten, Hunderte von Klassen, aber nur ein paar Dutzend Schnittstellen , also Rollen . Es gibt wenige Rollen, aber es gibt viele Möglichkeiten, sie zu kombinieren (Klassen).

Der springende Punkt ist, dass Sie nicht für jede Klasse Code schreiben müssen, um mit jeder anderen Klasse zu interagieren. Sie müssen lediglich mit ihren Rollen (Schnittstellen) interagieren.

Stellen Sie sich vor, Sie wären ein Haustiertrainer. Jedes der Haustiere, mit denen Sie arbeiten, kann verschiedene Fähigkeiten haben. Sie geraten mit Ihrem Nachbarn in einen freundschaftlichen Streit darüber, wessen Haustiere den meisten Lärm machen können. Um die Sache zu klären, stellen Sie einfach alle Haustiere auf, die „sprechen“ können, und geben ihnen den Befehl: „Sprich!“

Es ist dir egal, was für ein Tier sie sind oder welche anderen Fähigkeiten sie haben. Auch wenn sie einen Dreifachsalto machen können. In diesem besonderen Moment interessiert Sie nur ihre Fähigkeit, laut zu sprechen. So würde es im Code aussehen:

Code Beschreibung
interface CanSpeak
{
   void speak();
}
Die CanSpeakFähigkeit. Diese Schnittstelle versteht den Befehl to speak, was bedeutet, dass sie über eine entsprechende Methode verfügt.
class Cat implements CanSpeak
{
   void speak()
   {
      println("MEOW");
   }
}

class Dog implements CanSpeak
{
   void speak()
   {
      println("WOOF");
   }
}

class Fish
{
   ...
}
Tiere, die diese Funktion haben.

Um das Verständnis zu erleichtern, haben wir die Klassennamen auf Englisch angegeben. Dies ist in Java erlaubt, aber höchst unerwünscht.













Unser hat nicht die Fähigkeit zu sprechen (implementiert die Schnittstelle Fishnicht ).CanSpeak

public static void main(String[] args)
{
   // Add all the animals to the list
   ArrayList pets = new ArrayList();
   pets.add(new Cat());
   pets.add(new Dog());
   pets.add(new Fish());

   // If the ability exists, then make a sound
   for(Object pet: pets)
   {
      if (pet instanceof CanSpeak)
      {
         CanSpeak loudmouth = (CanSpeak) pet;
         loudmouth.speak();
      }
   }
}
Und wie geben wir ihnen den Befehl?

Wenn die Anzahl der Klassen in Ihren Programmen Tausende erreicht, werden Sie ohne Schnittstellen nicht mehr leben können. Anstatt die Interaktion von Tausenden von Klassen zu beschreiben, reicht es aus, die Interaktion von einigen Dutzend Schnittstellen zu beschreiben – das vereinfacht das Leben erheblich.

Und in Kombination mit Polymorphismus ist dieser Ansatz im Allgemeinen ein voller Erfolg.



3. Die defaultImplementierung von Schnittstellenmethoden

Abstrakte Klassen können Variablen und Implementierungen von Methoden haben, aber keine Mehrfachvererbung. Schnittstellen können keine Variablen oder Implementierungen von Methoden enthalten, diese können jedoch mehrfach vererbt werden.

Die Situation wird in der folgenden Tabelle ausgedrückt:

Fähigkeit/Eigenschaft Abstrakte Klassen Schnittstellen
Variablen
Methodenimplementierung
Mehrfachvererbung

Daher wollten einige Programmierer unbedingt, dass Schnittstellen über die Möglichkeit zur Methodenimplementierung verfügen. Die Möglichkeit, eine Methodenimplementierung hinzuzufügen, bedeutet jedoch nicht, dass immer eine hinzugefügt wird. Fügen Sie es hinzu, wenn Sie möchten. Oder wenn nicht, dann nicht.

Darüber hinaus sind Probleme bei der Mehrfachvererbung vor allem auf Variablen zurückzuführen. Auf jeden Fall haben sie das beschlossen und getan. Beginnend mit JDK 8 führte Java die Möglichkeit ein, Methodenimplementierungen zu Schnittstellen hinzuzufügen.

Hier ist eine aktualisierte Tabelle (für JDK 8 und höher):

Fähigkeit/Eigenschaft Abstrakte Klassen Schnittstellen
Variablen
Methodenimplementierung
Mehrfachvererbung

Nun können Sie sowohl für abstrakte Klassen als auch für Schnittstellen Methoden mit oder ohne Implementierung deklarieren. Und das sind hervorragende Neuigkeiten!

In abstrakten Klassen muss Methoden ohne Implementierung das abstractSchlüsselwort vorangestellt werden. Sie müssen vor Methoden mit einer Implementierung nichts hinzufügen. Bei Schnittstellen ist das Gegenteil der Fall. Wenn eine Methode keine Implementierung hat, sollte nichts hinzugefügt werden. Wenn es jedoch eine Implementierung gibt, defaultmuss das Schlüsselwort hinzugefügt werden.

Der Einfachheit halber stellen wir diese Informationen in der folgenden kleinen Tabelle dar:

Fähigkeit/Eigenschaft Abstrakte Klassen Schnittstellen
Methoden ohne Implementierung abstract
Methoden mit einer Implementierung default

Problem

Durch die Verwendung von Schnittstellen mit Methoden können große Klassenhierarchien erheblich vereinfacht werden. Beispielsweise können die Zusammenfassung InputStreamund OutputStreamdie Klassen als Schnittstellen deklariert werden! Dadurch können wir sie viel häufiger und komfortabler nutzen.

Aber es gibt bereits zig Millionen (Milliarden?) Java-Klassen auf der Welt. Und wenn Sie anfangen, Standardbibliotheken zu ändern, kann es passieren, dass etwas kaputt geht. Wie alles! 😛

Um bestehende Programme und Bibliotheken nicht versehentlich zu beschädigen, wurde beschlossen, dass Methodenimplementierungen in Schnittstellen die niedrigste Vererbungspriorität haben .

Wenn beispielsweise eine Schnittstelle eine andere Schnittstelle erbt, die über eine Methode verfügt, und die erste Schnittstelle dieselbe Methode deklariert, jedoch ohne Implementierung, erreicht die Methodenimplementierung der geerbten Schnittstelle die erbende Schnittstelle nicht. Beispiel:

interface Pet
{
   default void meow()
   {
      System.out.println("Meow");
   }
}

interface Cat extends Pet
{
   void meow(); // Here we override the default implementation by omitting an implementation
}

class Tom implements Cat
{
}

Der Code lässt sich nicht kompilieren, da die TomKlasse die Methode nicht implementiert meow().