Statische und Standardmethoden in Schnittstellen in Java

1. Übersicht

Java 8 brachte einige brandneue Funktionen auf den Tisch, darunter Lambda-Ausdrücke, funktionale Schnittstellen, Methodenreferenzen, Streams, optionale sowie statische und Standardmethoden in Schnittstellen.

Einige von ihnen wurden bereits in diesem Artikel behandelt. Dennoch verdienen statische und Standardmethoden in Schnittstellen einen genaueren Blick auf sich.

In diesem Artikel werden wir ausführlich erläutern, wie statische und Standardmethoden in Schnittstellen verwendet werden, und einige Anwendungsfälle durchgehen, in denen sie nützlich sein können.

2. Warum Standardmethoden in Schnittstellen benötigt werden

Wie normale Schnittstellenmethoden sind Standardmethoden implizit öffentlich - der öffentliche Modifikator muss nicht angegeben werden.

Im Gegensatz zu normalen Schnittstellenmethoden werden sie am Anfang der Methodensignatur mit dem Standardschlüsselwort deklariert und bieten eine Implementierung .

Sehen wir uns ein einfaches Beispiel an:

public interface MyInterface { // regular interface methods default void defaultMethod() { // default method implementation } }

Der Grund, warum Standardmethoden in der Java 8-Version enthalten waren, liegt auf der Hand.

In einem typischen Entwurf, der auf Abstraktionen basiert und bei dem eine Schnittstelle eine oder mehrere Implementierungen aufweist, werden alle Implementierungen gezwungen, diese ebenfalls zu implementieren, wenn der Schnittstelle eine oder mehrere Methoden hinzugefügt werden. Andernfalls wird das Design nur zusammenbrechen.

Standardschnittstellenmethoden sind eine effiziente Möglichkeit, dieses Problem zu beheben. Sie ermöglichen es uns, einer Schnittstelle neue Methoden hinzuzufügen, die in den Implementierungen automatisch verfügbar sind . Daher müssen die implementierenden Klassen nicht geändert werden.

Auf diese Weise bleibt die Abwärtskompatibilität sauber erhalten, ohne dass die Implementierer umgestaltet werden müssen.

3. Standardschnittstellenmethoden in Aktion

Um die Funktionalität der Standardschnittstellenmethoden besser zu verstehen , erstellen wir ein einfaches Beispiel.

Angenommen, wir haben eine naive Fahrzeugschnittstelle und nur eine Implementierung. Es könnte noch mehr geben, aber lassen Sie es uns so einfach halten:

public interface Vehicle { String getBrand(); String speedUp(); String slowDown(); default String turnAlarmOn() { return "Turning the vehicle alarm on."; } default String turnAlarmOff() { return "Turning the vehicle alarm off."; } }

Und schreiben wir die implementierende Klasse:

public class Car implements Vehicle { private String brand; // constructors/getters @Override public String getBrand() { return brand; } @Override public String speedUp() { return "The car is speeding up."; } @Override public String slowDown() { return "The car is slowing down."; } } 

Zuletzt definieren wir eine typische Hauptklasse , die eine Instanz von Car erstellt und deren Methoden aufruft:

public static void main(String[] args) { Vehicle car = new Car("BMW"); System.out.println(car.getBrand()); System.out.println(car.speedUp()); System.out.println(car.slowDown()); System.out.println(car.turnAlarmOn()); System.out.println(car.turnAlarmOff()); }

Bitte beachten Sie, wie die Standard - Methoden turnAlarmOn () und turnAlarmOff () aus unserem Fahrzeug Schnittstelle ist automatisch in der Autoklasse .

Wenn wir uns irgendwann dazu entschließen, der Fahrzeugschnittstelle weitere Standardmethoden hinzuzufügen , funktioniert die Anwendung weiterhin und wir müssen die Klasse nicht zwingen, Implementierungen für die neuen Methoden bereitzustellen.

Die typischste Verwendung von Standardmethoden in Schnittstellen besteht darin, einem bestimmten Typ schrittweise zusätzliche Funktionen bereitzustellen, ohne die implementierenden Klassen aufzuschlüsseln.

Darüber hinaus können sie verwendet werden, um zusätzliche Funktionen für eine vorhandene abstrakte Methode bereitzustellen :

public interface Vehicle { // additional interface methods double getSpeed(); default double getSpeedInKMH(double speed) { // conversion } }

4. Vererbungsregeln für mehrere Schnittstellen

Standardschnittstellenmethoden sind in der Tat eine nette Funktion, aber mit einigen erwähnenswerten Einschränkungen. Da Java - Klassen über mehrere Schnittstellen implementieren können, ist es wichtig zu wissen , was passiert , wenn eine Klasse implementiert mehrere Schnittstellen geschieht, die die gleichen definieren Standardmethoden .

Um dieses Szenario besser zu verstehen, definieren wir eine neue Alarmschnittstelle und überarbeiten die Fahrzeugklasse :

public interface Alarm { default String turnAlarmOn() { return "Turning the alarm on."; } default String turnAlarmOff() { return "Turning the alarm off."; } }

Mit dieser neuen Schnittstelle einen eigenen Satz definieren Standardmethoden, die Auto würde Klasse sowohl implementieren Fahrzeug und Alarm :

public class Car implements Vehicle, Alarm { // ... }

In diesem Fall wird der Code einfach nicht kompiliert, da es einen Konflikt gibt, der durch die Vererbung mehrerer Schnittstellen verursacht wird (auch bekannt als Diamond-Problem). Die Car- Klasse würde beide Sätze von Standardmethoden erben . Welche sollten dann genannt werden?

Um diese Unklarheit zu lösen, müssen wir explizit eine Implementierung für die Methoden bereitstellen:

@Override public String turnAlarmOn() { // custom implementation } @Override public String turnAlarmOff() { // custom implementation }

Wir können unsere Klasse auch die Standardmethoden einer der Schnittstellen verwenden lassen .

Sehen wir uns ein Beispiel an, das die Standardmethoden der Fahrzeugschnittstelle verwendet:

@Override public String turnAlarmOn() { return Vehicle.super.turnAlarmOn(); } @Override public String turnAlarmOff() { return Vehicle.super.turnAlarmOff(); } 

In ähnlicher Weise kann die Klasse die Standardmethoden verwenden, die in der Alarmschnittstelle definiert sind:

@Override public String turnAlarmOn() { return Alarm.super.turnAlarmOn(); } @Override public String turnAlarmOff() { return Alarm.super.turnAlarmOff(); } 

Darüber hinaus ist es sogar möglich, die Car- Klasse beide Standardmethoden verwenden zu lassen :

@Override public String turnAlarmOn() { return Vehicle.super.turnAlarmOn() + " " + Alarm.super.turnAlarmOn(); } @Override public String turnAlarmOff() { return Vehicle.super.turnAlarmOff() + " " + Alarm.super.turnAlarmOff(); } 

5. Statische Schnittstellenmethoden

Mit Java 8 können wir nicht nur Standardmethoden in Schnittstellen deklarieren, sondern auch statische Methoden in Schnittstellen definieren und implementieren .

Da statische Methoden nicht zu einem bestimmten Objekt gehören, sind sie nicht Teil der API der Klassen, die die Schnittstelle implementieren, und müssen unter Verwendung des Schnittstellennamens vor dem Methodennamen aufgerufen werden .

Um zu verstehen, wie statische Methoden in Schnittstellen funktionieren, überarbeiten wir die Fahrzeugschnittstelle und fügen ihr eine statische Dienstprogrammmethode hinzu:

public interface Vehicle { // regular / default interface methods static int getHorsePower(int rpm, int torque) { return (rpm * torque) / 5252; } } 

Das Definieren einer statischen Methode innerhalb einer Schnittstelle ist identisch mit dem Definieren einer Methode in einer Klasse. Darüber hinaus kann eine statische Methode innerhalb anderer statischer und Standardmethoden aufgerufen werden.

Angenommen, wir möchten die Leistung des Motors eines bestimmten Fahrzeugs berechnen. Wir rufen einfach die Methode getHorsePower () auf :

Vehicle.getHorsePower(2500, 480)); 

Die Idee hinter statischen Schnittstellenmethoden besteht darin, einen einfachen Mechanismus bereitzustellen, mit dem wir den Kohäsionsgrad eines Entwurfs erhöhen können, indem verwandte Methoden an einem einzigen Ort zusammengestellt werden, ohne dass ein Objekt erstellt werden muss.

So ziemlich das gleiche kann mit abstrakten Klassen erfolgen. Der Hauptunterschied liegt in der Tatsache, dass abstrakte Klassen Konstruktoren, Status und Verhalten haben können .

Darüber hinaus ermöglichen statische Methoden in Schnittstellen das Gruppieren verwandter Dienstprogrammmethoden, ohne dass künstliche Dienstprogrammklassen erstellt werden müssen, die lediglich Platzhalter für statische Methoden sind.

6. Fazit

In diesem Artikel haben wir uns eingehend mit der Verwendung statischer und Standardschnittstellenmethoden in Java 8 befasst. Auf den ersten Blick mag diese Funktion etwas schlampig aussehen, insbesondere aus objektorientierter puristischer Sicht. Im Idealfall sollten Schnittstellen das Verhalten nicht kapseln und nur zum Definieren der öffentlichen API eines bestimmten Typs verwendet werden.

Wenn es darum geht, die Abwärtskompatibilität mit vorhandenem Code aufrechtzuerhalten, sind statische und Standardmethoden jedoch ein guter Kompromiss.

Und wie üblich sind alle in diesem Artikel gezeigten Codebeispiele auf GitHub verfügbar.