wake-up-neo.com

Warum keine statischen Methoden in Interfaces, sondern statische Felder und innere Klassen? [vor Java 8]

Hier wurden einige Fragen gestellt, warum Sie keine statischen Methoden innerhalb von Schnittstellen definieren können, aber keine davon befasst sich mit einer grundlegenden Inkonsistenz: Warum können Sie statische Felder und statische innere Typen innerhalb einer Schnittstelle definieren, nicht aber statische Methoden?

Statische innere Typen sind vielleicht kein fairer Vergleich, da dies nur syntaktischer Zucker ist, der eine neue Klasse erzeugt, aber warum Felder, aber keine Methoden?

Ein Argument gegen statische Methoden in Interfaces ist, dass die von der JVM verwendete Strategie für die Auflösung virtueller Tabellen gebrochen wird. Sollte dies jedoch nicht gleichermaßen für statische Felder gelten, d. H.

Ich wünsche mir Konsistenz, und Java hätte entweder keine Statik einer beliebigen Form innerhalb einer Schnittstelle unterstützen sollen oder es sollte konsistent sein und sie zulassen. 

86
skaffman

Es wurde ein offizieller Vorschlag gemacht, um statische Methoden in Schnittstellen in Java 7 zuzulassen. Dieser Vorschlag wird unter Project Coin gemacht. 

Meine persönliche Meinung ist, dass es eine großartige Idee ist. Es gibt keine technischen Schwierigkeiten bei der Implementierung, und es ist eine sehr logische, vernünftige Sache. Es gibt mehrere Vorschläge in Project Coin, von denen ich hoffe, dass sie {niemals Teil der Java-Sprache werden, aber dies ist einer, der viele APIs bereinigen könnte. Zum Beispiel verfügt die Klasse Collections über statische Methoden zur Bearbeitung von List-Implementierungen. diese könnten in die List-Schnittstelle aufgenommen werden.


Update: Im Java Posse Podcast # 234 erwähnte Joe D'arcy den Vorschlag kurz und sagte, es sei "komplex" und würde es wahrscheinlich nicht unter Project Coin schaffen.


Update: Obwohl Java 8 nicht in Project Coin für Java 7 aufgenommen wurde, unterstützt Java 8 statische Funktionen in Schnittstellen.

49
erickson

Ich gehe mit meiner Lieblingstheorie zu dieser Theorie, die besagt, dass der Mangel an Konsistenz in diesem Fall eher eine Frage der Bequemlichkeit als des Designs oder der Notwendigkeit ist, da ich kein überzeugendes Argument gehört habe, dass es sich um eine der beiden handelt .

Statische Felder gibt es (a), weil sie in JDK 1.0 vorhanden waren und in JDK 1.0 viele zwielichtige Entscheidungen getroffen wurden, und (b) statische Endfelder in Interfaces die Java-Konstanten zu der Zeit am nächsten kamen.

Statische innere Klassen in Interfaces waren erlaubt, weil dies rein syntaktischer Zucker ist - die innere Klasse hat eigentlich nichts mit der Elternklasse zu tun.

Daher sind statische Methoden nicht erlaubt, nur weil es keinen zwingenden Grund gibt. Konsistenz ist nicht zwingend genug, um den Status Quo zu ändern. 

Natürlich könnte dies in zukünftigen JLS-Versionen erlaubt sein, ohne irgendetwas zu brechen.

39
skaffman

Es ist nie sinnvoll, eine statische Methode in einer Schnittstelle zu deklarieren. Sie können nicht mit dem normalen Aufruf MyInterface.staticMethod () ausgeführt werden. (EDIT: Seitdem der letzte Satz einige Leute verwirrt hat, führt der Aufruf von MyClass.staticMethod () genau die Implementierung von staticMethod für MyClass aus. Wenn MyClass keine Schnittstelle ist, kann dies nicht geschehen!) Dann müssen Sie die tatsächliche Klasse kennen, es ist also unerheblich, ob die Schnittstelle sie enthält oder nicht.

Noch wichtiger ist, statische Methoden werden niemals überschrieben, und wenn Sie versuchen, Folgendes zu tun:

MyInterface var = new MyImplementingClass();
var.staticMethod();

die statischen Regeln besagen, dass die im deklarierten Typ von var definierte Methode ausgeführt werden muss. Da dies eine Schnittstelle ist, ist dies nicht möglich. 

Sie können das statische Schlüsselwort natürlich immer aus der Methode entfernen. Alles wird gut funktionieren. Sie müssen möglicherweise einige Warnungen unterdrücken, wenn sie von einer Instanzmethode aufgerufen werden.

Um einige der folgenden Kommentare zu beantworten, besteht der Grund, warum Sie "result = MyInterface.staticMethod ()" nicht ausführen können, darin, dass die Version der in MyInterface definierten Methode ausgeführt werden muss. Es kann jedoch keine Version in MyInterface definiert werden, da es sich um eine Schnittstelle handelt. Es hat keinen Code per Definition.

14
DJClayworth

Schnittstellen dienen dazu, einen Vertrag zu definieren, ohne eine Implementierung bereitzustellen. Daher können Sie keine statischen Methoden verwenden, da sie bereits eine Implementierung in der Schnittstelle haben müssen, da Sie statische Methoden nicht überschreiben können. Bei Feldern sind nur statische final fields zulässig, bei denen es sich im Wesentlichen um Konstanten handelt. Die Konstanten dienen dazu, die Schnittstelle ohne magische Zahlen zu definieren.

Übrigens, es ist nicht notwendig, static final-Modifizierer explizit für Felder in Schnittstellen anzugeben, da nur statische abschließende Felder zulässig sind.

6
Alexander

Dies ist ein alter Thread, aber dies ist eine sehr wichtige Frage für alle. Da ich das heute nur bemerkt habe, versuche ich es auf sauberere Weise zu erklären:

Der Hauptzweck der Schnittstelle besteht darin, etwas bereitzustellen, das nicht umsetzbar ist 

statische Methoden erlaubt sein 

sie können diese Methode dann mit interfaceName.staticMethodName () aufrufen, aber diese Methode ist nicht implementiert und enthält nichts. Es ist also sinnlos, statische Methoden zuzulassen. Deshalb bieten sie dies überhaupt nicht an.

statische Felder sind erlaubt

da Felder nicht implementierbar sind, können Sie durch Implementieren keine logischen Operationen in Feld ausführen. Sie können Operationen auch auf Feld ausführen. Sie ändern also nicht das Verhalten des Feldes, weshalb sie zulässig sind.

Innere Klassen sind erlaubt 

Innere Klassen sind zulässig, da nach der Kompilierung eine andere Klassendatei der Inner-Klasse erstellt wird, z. B. InterfaceName $ InnerClassName.class . Sie bieten also grundsätzlich eine Implementierung in verschiedenen Entitäten, jedoch nicht in der Schnittstelle. Somit ist die Implementierung in inneren Klassen vorgesehen.

Ich hoffe das würde helfen.

6
user1707035

Es gibt keinen wirklichen Grund dafür, keine statischen Methoden in Schnittstellen zu verwenden, es sei denn, die Entwickler von Java-Sprachen wollten dies nicht. Aus technischer Sicht wäre es sinnvoll, sie zuzulassen. Schließlich kann sie auch eine abstrakte Klasse haben. Ich gehe davon aus, habe es aber nicht getestet, dass Sie Bytecode "handcraft" können, wobei die Schnittstelle eine statische Methode hat und imho problemlos funktionieren sollte, die Methode aufzurufen und/oder die Schnittstelle wie gewohnt zu verwenden.

3
Angel O'Sphere

Manchmal gibt es Gründe, warum jemand von statischen Methoden profitieren kann. Sie können als Factory-Methoden für die Klassen verwendet werden, die die Schnittstelle implementieren. Dies ist beispielsweise der Grund, warum wir jetzt in Openjdk die Collection-Schnittstelle und die Collections-Klasse haben. Daher gibt es wie immer Problemumgehungen. Versehen Sie eine andere Klasse mit einem privaten Konstruktor, der als "Namespace" für die statischen Methoden dient.

3
nikolavp

Vor Java 5 war eine übliche Verwendung für statische Felder:

interface HtmlConstants {
    static String OPEN = "<";
    static String SLASH_OPEN = "</";
    static String CLOSE = ">";
    static String SLASH_CLOSE = " />";
    static String HTML = "html";
    static String BODY = "body";
    ...
}

public class HtmlBuilder implements HtmlConstants { // implements ?!?
    public String buildHtml() {
       StringBuffer sb = new StringBuffer();
       sb.append(OPEN).append(HTML).append(CLOSE);
       sb.append(OPEN).append(BODY).append(CLOSE);
       ...
       sb.append(SLASH_OPEN).append(BODY).append(CLOSE);
       sb.append(SLASH_OPEN).append(HTML).append(CLOSE);
       return sb.toString();
    }
}

Dies bedeutete, dass HtmlBuilder nicht jede Konstante qualifizieren musste. Daher könnte OPEN anstelle von HtmlConstants.OPEN verwendet werden.

Die Verwendung von Werkzeugen auf diese Weise ist letztlich verwirrend.

Jetzt haben wir mit Java 5 die Syntax import static, um denselben Effekt zu erzielen:

private final class HtmlConstants {
    ...
    private HtmlConstants() { /* empty */ }
}

import static HtmlConstants.*;
public class HtmlBuilder { // no longer uses implements
    ...
}
3
toolkit

Ich frage mich oft, warum statische Methoden überhaupt? Sie haben ihre Verwendung, aber Methoden auf Paket-/Namensraumebene würden wahrscheinlich 80 der statischen Methoden abdecken.

2
Vasil

Zwei Hauptgründe fallen ein:

  1. Statische Methoden in Java können nicht durch Unterklassen überschrieben werden. Dies ist bei Methoden eine viel größere Herausforderung als bei statischen Feldern. In der Praxis wollte ich niemals ein Feld in einer Unterklasse überschreiben, aber ich überschreibe immer die Methoden. Mit statischen Methoden kann also verhindert werden, dass eine Klasse, die das Interface implementiert, ihre eigene Implementierung dieses Verfahrens bereitstellt.

  2. Schnittstellen sollen keinen Code haben; dafür sind abstrakte Klassen gedacht. Der springende Punkt einer Benutzeroberfläche besteht darin, Sie über möglicherweise nicht zusammenhängende Objekte sprechen zu lassen, bei denen alle über bestimmte Methoden verfügen. Die Implementierung einer solchen Methode liegt tatsächlich außerhalb der Grenzen der Schnittstellen.

1
Eli Courtwright

Statische Methoden sind an eine Klasse gebunden. In Java ist eine Schnittstelle technisch keine Klasse, sie ist ein Typ, jedoch keine Klasse (daher werden die Schlüsselwörter implementiert und Schnittstellen erweitern Object nicht). Da Schnittstellen keine Klassen sind, können sie keine statischen Methoden haben, da keine eigentliche Klasse zum Anhängen vorhanden ist.

Sie können InterfaceName.class aufrufen, um das der Schnittstelle entsprechende Klassenobjekt abzurufen. Die Klassenklasse gibt jedoch ausdrücklich an, dass es Klassen und Schnittstellen in einer Java-Anwendung darstellt. Die Schnittstelle selbst wird jedoch nicht als Klasse behandelt. Daher können Sie keine statische Methode anfügen.

1
MetroidFan2002

Die statische Methode der Java 1.8-Schnittstelle ist nur für Schnittstellenmethoden sichtbar, wenn wir die Methode MethodeSta1 () aus der InterfaceExample-Klasse entfernen,. Wie andere statische Methoden können auch statische Methoden der Schnittstelle unter Verwendung des Klassennamens verwendet werden. Eine gültige Anweisung lautet beispielsweise: Exp1.methodSta1 ();

Nach einem Blick auf das folgende Beispiel können wir sagen: 1) Die statische Methode der Java-Schnittstelle ist Teil der Schnittstelle und 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, Protokoll usw.

3) Die statische Methode der Java-Schnittstelle hilft uns bei der Bereitstellung von Sicherheit, da Implementierungsklassen (InterfaceExample) sie nicht überschreiben lassen.

4) Wir können keine statische Schnittstellenmethode für Objektklassenmethoden definieren. Der Compiler-Fehler wird als "Diese statische Methode kann die Instanzmethode nicht vor Objekt verbergen" angezeigt. Dies liegt daran, dass dies in Java nicht zulässig ist, da Object die Basisklasse für alle Klassen ist und wir keine statische Methode auf Klassenebene und keine andere Instanzmethode mit derselben Signatur verwenden können.

5) Wir können statische Methoden der Java-Schnittstelle verwenden, um Dienstprogrammklassen wie Collections zu entfernen und alle statischen Methoden auf die entsprechende Schnittstelle () Zu verschieben. das wäre leicht zu finden und zu verwenden.

public class InterfaceExample implements exp1 {

    @Override
    public void method() {
        System.out.println("From method()");
    }

    public static void main(String[] args) {
        new InterfaceExample().method2();
        InterfaceExample.methodSta2();      //  <---------------------------    would not compile
        // methodSta1();                        //  <---------------------------    would not compile
        exp1.methodSta1();
    }

    static void methodSta2() {          //          <-- it compile successfully but it can't be overridden in child classes
        System.out.println("========= InterfaceExample :: from methodSta2() ======");
    }
}


interface exp1 {

    void method();
    //protected void method1();         //          <--      error
    //private void method2();           //          <--      error
    //static void methodSta1();         //          <--      error it require body in Java 1.8

    static void methodSta1() {          //          <-- it compile successfully but it can't be overridden in child classes
        System.out.println("========= exp1:: from methodSta1() ======");
    }

    static void methodSta2() {          //          <-- it compile successfully but it can't be overridden in child classes
        System.out.println("========= exp1:: from methodSta2() ======");
    }

    default void method2() { System.out.println("---  exp1:: from method2() ---");}
    //synchronized default void method3() { System.out.println("---");}             // <-- Illegal modifier for the interface method method3; only public, abstract, default, static 
                                                                                // and strictfp are permitted
    //final default void method3() { System.out.println("---");} //             <--      error
}
0
Ashish Sharma

In einer Schnittstelle können nur statische abschließende Felder deklariert werden (ähnlich wie bei Methoden, die öffentlich sind, auch wenn Sie das Schlüsselwort "public" nicht angeben, statische Felder sind mit oder ohne Schlüsselwort "final").

Dies sind nur Werte und werden wortwörtlich kopiert, wo auch immer sie zur Kompilierzeit verwendet werden, so dass Sie zur Laufzeit niemals statische Felder "aufrufen". Eine statische Methode hätte nicht die gleiche Semantik, da das Aufrufen einer Schnittstelle ohne Implementierung erforderlich wäre, was Java nicht zulässt.

0
cynicalman

Ich bin der Meinung, dass auf statische Methoden ohne das Erstellen eines Objekts zugegriffen werden kann, und die Schnittstelle erlaubt es nicht, ein Objekt zu erstellen, das die Programmierer daran hindert, die Schnittstellenmethoden direkt zu verwenden, anstatt von ihrer implementierten Klasse .. .. Wenn Sie jedoch eine statische Methode in definieren Über eine Schnittstelle können Sie ohne Implementierung direkt darauf zugreifen. Daher sind statische Methoden in Schnittstellen nicht zulässig. Ich glaube nicht, dass Konsistenz ein Problem sein sollte. 

0
prerana gupta

Der Grund ist, dass alle in einer Schnittstelle definierten Methoden abstrakt sind, unabhängig davon, ob Sie diesen Modifikator explizit deklarieren. Eine abstrakte statische Methode ist keine zulässige Kombination von Modifizierern, da statische Methoden nicht überschrieben werden können.

Warum Schnittstellen statische Felder zulassen. Ich habe das Gefühl, dass ein "Feature" betrachtet werden sollte. Die einzige Möglichkeit, die ich mir vorstellen kann, wäre die Gruppierung von Konstanten, an denen Implementierungen der Schnittstelle interessiert wären.

Ich stimme zu, dass Konsistenz ein besserer Ansatz gewesen wäre. In einer Schnittstelle sollten keine statischen Member zulässig sein.

0
laz