1. Einführung in Schnittstellen

Heute ist Ihr Tag des Wissens. Ein weiteres neues und interessantes Thema sind Schnittstellen.

Das Konzept einer Schnittstelle ist das Kind der Prinzipien der Abstraktion und des Polymorphismus. Eine Schnittstelle ist einer abstrakten Klasse sehr ähnlich, in der alle Methoden abstrakt sind. Es wird auf die gleiche Weise wie eine Klasse deklariert, wir verwenden jedoch das interfaceSchlüsselwort.

interface Feline
{
   void purr();
   void meow();
   void growl();
}

Hier sind einige nützliche Fakten über Schnittstellen:

1. Deklarieren einer Schnittstelle

interface Drawable
{
   void draw();
}

interface HasValue
{
   int getValue();
}
  1. Anstelle des classSchlüsselworts schreiben wir interface.
  2. abstractEs enthält nur abstrakte Methoden (schreiben Sie das Schlüsselwort nicht )
  3. Tatsächlich verfügen Schnittstellen über allepublic Methoden
2. Schnittstellenvererbung

Eine Schnittstelle kann nur Schnittstellen erben. Aber eine Schnittstelle kann viele Eltern haben. Eine andere Möglichkeit, dies auszudrücken, besteht darin, zu sagen, dass Java über eine Mehrfachvererbung von Schnittstellen verfügt. Beispiele:

interface Piece extends Drawable, HasValue
{
   int getX();
   int getY();
}

3. Klassen von Schnittstellen erben

Eine Klasse kann mehrere Schnittstellen erben (nur von einer Klasse). Dies geschieht über das implementsSchlüsselwort. Beispiel:

abstract class ChessItem implements Drawable, HasValue
{
   private int x, y, value;
   public int getValue()
   {
      return value;
   }

   public int getX()
   {
      return x;
   }

   public  int getY()
   {
      return y;
   }
}

Die ChessItem-Klasse ist abstrakt deklariert: Sie implementiert alle geerbten Methoden außer draw. Mit anderen Worten, die ChessItemKlasse enthält eine abstrakte Methode – draw().

Die technische Bedeutung der Schlüsselwörter extendsund implementsist dieselbe: Beide sind Vererbung. Die Unterscheidung wurde vorgenommen, um die Lesbarkeit des Codes zu verbessern. Wir sagen auch, dass Klassen vererbt werden (via extends) und Schnittstellen implementiert werden (via implements).

4. Variablen

Hier ist das Wichtigste: Gewöhnliche Variablen können nicht in Schnittstellen deklariert werden (statische Variablen hingegen schon).

Aber warum brauchen wir Schnittstellen? Wann werden sie verwendet? Schnittstellen haben gegenüber Klassen zwei große Vorteile:



2. Trennung der „Beschreibung von Methoden“ von ihrer Implementierung.

Zuvor haben wir gesagt, dass Ihre Methoden mit dem Schlüsselwort gekennzeichnet werden müssen, wenn Sie zulassen möchten, dass die Methoden Ihrer Klasse von anderen Klassen aufgerufen werden public. Wenn Sie möchten, dass einige dieser Methoden nur innerhalb Ihrer Klasse aufgerufen werden, müssen Sie sie mit dem privateSchlüsselwort kennzeichnen. Mit anderen Worten: Wir unterteilen die Methoden der Klasse in zwei Kategorien: „zur Nutzung durch jedermann“ und „nur für unseren eigenen Gebrauch“.

Schnittstellen tragen dazu bei, diesen Bereich weiter zu stärken. Wir werden eine spezielle „Klasse für jedermanns Nutzung“ sowie eine zweite Klasse „nur für unseren eigenen Gebrauch“ erstellen, die die erste Klasse erben wird. So ungefähr würde es aussehen:

Vor Nach
class Student
{
   private String name;
   public Student(String name)
   {
      this.name = name;
   }

   public String getName()
   {
      return this.name;
   }

   private void setName(String name)
   {
      this.name = name;
   }
interface Student
{
   public String getName();
}

class StudentImpl implements Student
{
   private String name;
   public StudentImpl(String name)
   {
      this.name = name;
   }

   public String getName()
   {
      return this.name;
   }

   private void setName(String name)
   {
      this.name = name;
   }
}
public static void main(String[] args)
{
   Student student = new Student("Alibaba");
   System.out.println(student.getName());
}
public static void main(String[] args)
{
   Student student = new StudentImpl("Ali")
   System.out.println(student.getName());
}

Wir teilen unsere Klasse in zwei Teile auf: eine Schnittstelle und eine Klasse , die die Schnittstelle erbt . Und was ist hier der Vorteil?

Viele verschiedene Klassen können dieselbe Schnittstelle implementieren (erben). Und jeder kann sein eigenes Verhalten haben. Beispielsweise ArrayList LinkedListgibt es zwei unterschiedliche Implementierungen der ListSchnittstelle.

Somit verbergen wir nicht nur die verschiedenen Implementierungen, sondern auch die implementierende Klasse selbst (da wir im Code nur die Schnittstelle benötigen). Dadurch sind wir sehr flexibel: Direkt während das Programm läuft, können wir ein Objekt durch ein anderes ersetzen und so das Verhalten eines Objekts ändern, ohne dass sich dies auf alle Klassen auswirkt, die es verwenden.

In Kombination mit Polymorphismus ist dies eine sehr leistungsfähige Technik. Im Moment ist es alles andere als offensichtlich, warum Sie dies tun sollten. Sie müssen zunächst Programme mit Dutzenden oder Hunderten von Klassen kennenlernen, um zu verstehen, dass Schnittstellen Ihr Leben viel einfacher machen können als ohne sie.


3. Mehrfachvererbung

In Java können alle Klassen nur eine übergeordnete Klasse haben. In anderen Programmiersprachen können Klassen häufig mehrere übergeordnete Klassen haben. Das ist sehr praktisch, bringt aber auch viele Probleme mit sich.

Die Entwickler von Java haben einen Kompromiss gefunden: Sie haben die Mehrfachvererbung von Klassen verboten, aber die Mehrfachvererbung von Schnittstellen zugelassen. Eine Schnittstelle kann mehrere übergeordnete Schnittstellen haben. Eine Klasse kann mehrere übergeordnete Schnittstellen haben, aber nur eine übergeordnete Klasse.

Warum haben sie die Mehrfachvererbung von Klassen verboten, aber die Mehrfachvererbung von Schnittstellen zugelassen? Wegen des sogenannten Diamanten-Vererbungsproblems:

Mehrfachvererbung

Wenn die B-Klasse die A-Klasse erbt, weiß sie nichts über die C- und D-Klassen. Es verwendet also die Variablen der A-Klasse nach eigenem Ermessen. Die C-Klasse macht dasselbe: Sie verwendet die Variablen der A-Klasse, jedoch auf andere Weise. Und das alles führt zu einem Konflikt in der D-Klasse.

Schauen wir uns das folgende einfache Beispiel an. Nehmen wir an, wir haben 3 Klassen:

class Data
{
   protected int value;
}
class XCoordinate extends Data
{
   public void setX (int x) { value = x;}
   public int getX () { return value;}
}
class YCoordinate extends Data
{
   public void setY (int y) { value = y;}
   public int getY () { return value; }
}

Die Datenklasse speichert die valueVariable. Seine Nachkommenklasse XCoordinate verwendet diese Variable zum Speichern des xWerts, und die YCoordinateNachkommenklasse verwendet sie zum Speichern des yWerts.

Und es funktioniert. Separat. XCoordinateWenn wir jedoch möchten, dass die XYCoordinates-Klasse sowohl die als auch die Klassen erbt YCoordinate, erhalten wir fehlerhaften Code. Diese Klasse verfügt über die Methoden ihrer Vorfahrenklassen, diese funktionieren jedoch nicht ordnungsgemäß, da sie dieselben haben value variable.

Da Schnittstellen jedoch keine Variablen haben können, kann es bei ihnen nicht zu Konflikten dieser Art kommen. Dementsprechend ist eine Mehrfachvererbung von Schnittstellen zulässig.