Ich habe erst kürzlich bemerkt, dass es eine Option gibt, statische Methoden in Schnittstellen zu haben. Wie bei statischen Schnittstellenfeldern gibt es ein interessantes Verhalten: Diese werden nicht vererbt.
Ich bin mir nicht sicher, ob es in den tatsächlichen Schnittstellen, die implementiert werden sollen, nützlich ist. Es ermöglicht dem Programmierer jedoch, Schnittstellen zu erstellen, die nur Hüllkurven für statische Inhalte sind, wie z. B. Utility-Klassen.
Ein einfaches Beispiel ist nur ein Umschlag für globale Konstanten. Im Vergleich zu einer Klasse können Sie das fehlende Boilerplate von leicht bemerken, public static final
da diese angenommen werden (was es weniger ausführlich macht).
public interface Constants {
String LOG_MESSAGE_FAILURE = "I took an arrow to the knee.";
int DEFAULT_TIMEOUT_MS = 30;
}
Sie könnten auch etwas komplexeres machen, wie diese Pseudo-Enumeration von Konfigurationsschlüsseln.
public interface ConfigKeys {
static createValues(ConfigKey<?>... values) {
return Collections.unmodifiableSet(new HashSet(Arrays.asList(values)));
}
static ConfigKey<T> key(Class<T> clazz) {
return new ConfigKey<>(clazz);
}
class ConfigKey<T> {
private final Class<T> type;
private ConfigKey(Class<T> type) {
this.type = type;
}
private Class<T> getType() {
return type;
}
}
}
import static ConfigKeys.*;
public interface MyAppConfigKeys {
ConfigKey<Boolean> TEST_MODE = key(Boolean.class);
ConfigKey<String> COMPANY_NAME = key(String.class);
Set<ConfigKey<?>> VALUES = createValues(TEST_MODE, COMPANY_VALUE);
static values() {
return VALUES;
}
}
Sie können auf diese Weise auch eine Dienstprogramm- "Klasse" erstellen. In Dienstprogrammen ist es jedoch oft nützlich, private oder geschützte Hilfsmethoden zu verwenden, was in Klassen nicht ganz möglich ist.
Ich halte es für eine nette Neuerung, und insbesondere die Tatsache, dass die statischen Member nicht vererbt werden, ist ein interessantes Konzept, das nur für Schnittstellen eingeführt wurde.
Ich frage mich, ob Sie es für eine gute Praxis halten können. Während Code-Stil und Best Practices nicht selbstverständlich sind und es Raum für Meinungen gibt, gibt es meiner Meinung nach in der Regel gültige Gründe, die die Meinung stützen.
Ich interessiere mich mehr für die Gründe (nicht), Muster wie diese beiden zu verwenden.
Beachten Sie, dass ich diese Schnittstellen nicht implementieren möchte. Sie sind lediglich ein Umschlag für ihren statischen Inhalt. Ich beabsichtige nur, die Konstanten oder Methoden zu verwenden und möglicherweise den statischen Import zu verwenden.
default
Methoden. Ich spreche überstatic
Methoden und Felder. Diese werden nicht vererbt, sodass sie die Mehrfachvererbung nicht aufheben.Antworten:
Das Setzen von Konstanten auf Schnittstellen wird als die bezeichnet,
Constant Interface Antipattern
da Konstanten häufig nur ein Implementierungsdetail sind. Weitere Nachteile sind im Wikipedia-Artikel über die Constant-Oberfläche zusammengefasst .In der Java-Dokumentation heißt es in der Tat , dass statische Methoden das Organisieren von Hilfsmethoden erleichtern können, beispielsweise beim Aufrufen von Hilfsmethoden aus Standardmethoden.
quelle
Wie in der Frage angegeben, soll die Schnittstelle nicht implementiert (oder instanziiert) werden. Also könnten wir es mit einer Klasse vergleichen, die einen privaten Konstruktor hat:
super()
to call erweitert werden, aber die Schnittstelle kann "implementiert" werdennew MyInterface() {};
Dieser Vergleich ist zugunsten der Klasse, da er mehr Kontrolle ermöglicht. Das heißt, Klasse ist nicht dazu gedacht, statische Inhalte zu besitzen, man würde erwarten, dass es Instanzen gibt. Nun, es gibt keine perfekte Option.
Es gibt auch eine seltsame Sache bei der Vererbung von der "statischen Schnittstelle":
Dies könnte Gründe dafür sein, es als schlechtes Muster zu betrachten und in diesen Fällen weiterhin statische Klassen zu verwenden. Für jemanden, der süchtig nach syntaktischem Zucker ist, kann es jedoch verlockend sein, auch mit den Nachteilen.
quelle
Als @MarkusPscheidt ist diese Idee im Wesentlichen eine Erweiterung des Constant Interface Antipatterns. Dieser Ansatz wurde ursprünglich häufig verwendet, um die Vererbung eines einzelnen Satzes von Konstanten durch viele unterschiedliche Klassen zu ermöglichen. Der Grund dafür, dass dies letztendlich als Antimuster angesehen wurde, lag in den Problemen, die bei der Verwendung dieses Ansatzes in realen Projekten auftraten. Ich sehe keinen Grund zu der Annahme, dass sich diese Probleme nur auf Konstanten beziehen würden.
Wahrscheinlich noch wichtiger ist, dass es wirklich nicht nötig ist, dies zu tun. Verwenden Sie stattdessen statische Importe und geben Sie genau an, was Sie von wo importieren.
quelle
interface ColorFilter {Image applyGradient(int colorSpace, int width, byte[] pixels); }
. Ich kann mir vorstellen , es gibt einige andere Konstanten zu seinRGB
,RGBA
,CMYK
,GREYSCALE
,INDEXED
usw.Ich würde sagen, wenn Sie daran interessiert sind, wie die neue Funktion richtig verwendet wird, werfen Sie einen Blick auf den Code im JDK. Standardmethoden für Schnittstellen werden sehr häufig verwendet und sind leicht zu finden, statische Methoden für Schnittstellen scheinen jedoch sehr selten zu sein. Einige Beispiele hierfür sind
java.time.chrono.Chronology
,java.util.Comparator
,java.util.Map
und schon einige Schnittstellen injava.util.function
undjava.util.stream
.Bei den meisten Beispielen, die ich mir angesehen habe, handelt es sich um die Verwendung von APIs, die wahrscheinlich sehr häufig sind: Konvertierung zwischen verschiedenen Typen in der Zeit-API, zum Beispiel für Vergleiche, die wahrscheinlich häufig zwischen Objekten durchgeführt werden, die an Funktionen oder Objekte in übergeben werden Sammlungen. Zum Mitnehmen: Wenn ein Teil Ihrer API flexibel sein muss, Sie jedoch beispielsweise 80% der Anwendungsfälle mit einer Handvoll Standardeinstellungen abdecken können, sollten Sie statische Methoden für Ihre Schnittstellen in Betracht ziehen. Angesichts der Tatsache, dass diese Funktion im JDK anscheinend selten verwendet wird, wäre ich sehr konservativ, wenn ich sie in meinem eigenen Code verwende.
Ihre Beispiele sehen nicht so aus, wie ich es im JDK sehe. Für diese speziellen Fälle sollten Sie mit ziemlicher Sicherheit eine erstellen
enum
, die die gewünschte Schnittstelle implementiert. Eine Schnittstelle beschreibt eine Reihe von Verhaltensweisen und hat wirklich nichts damit zu tun, eine Sammlung ihrer Implementierungen zu verwalten.quelle
Wie wäre es mit Kompatibilität mit älteren JVMs?
Nein. Es ist eine rückwärts inkompatible Änderung, die die Ausdruckskraft der Sprache um ein Vielfaches erhöht. Zwei Daumen runter.
Ich empfehle dringend, Klassen zu verwenden, um Implementierungsdetails zu enthalten. Eine Schnittstelle soll eigentlich nur sagen, dass "dieses Objekt Operationen XYZ unterstützt", und das hat nichts mit statischen Methoden zu tun, die Sie möglicherweise in die Schnittstellendeklaration einfügen möchten. Diese Funktion ist wie eine Liege mit eingebautem Minikühlschrank. Sicher hat es einige Nischenverwendungen, aber es zieht nicht genug Gewicht, um den Mainstream zu verdienen.
UPDATE: Bitte keine Downvotes mehr. Offensichtlich denken einige Leute, dass statische Methoden in Schnittstellen die Knie der Biene sind, und ich kapituliere hiermit. Ich würde diese Antwort gleich löschen, aber die Kommentare im Anhang sind eine interessante Diskussion.
quelle