Warum kann ich keine statischen Methoden in einer Schnittstelle deklarieren?

150

Das Thema sagt das meiste aus - was ist der Grund dafür, dass statische Methoden in einer Schnittstelle nicht deklariert werden können?

public interface ITest {
    public static String test();
}

Der obige Code gibt mir den folgenden Fehler (zumindest in Eclipse): "Unzulässiger Modifikator für die Schnittstellenmethode ITest.test (); nur public & abstract sind zulässig".

Henrik Paul
quelle
2
Bitte akzeptieren Sie die Antwort von Espo nicht, da sie fehlerhaft ist. Eine Schnittstelle verfügt über eine Klassendatei, die die Implementierung einer statischen Methode enthalten kann (sofern der Java-Designer dies zulässt), sodass die Implementierung der statischen Methode problemlos aufgelöst werden kann. Es funktioniert genau wie bei anderen statischen Klassen.
Mnementh
Ich stimme der Antwort von "erickson" stackoverflow.com/questions/512877/…
Maverick
9
Dies wird übrigens in Java 8 verfügbar sein.
m0skit0
1
@Vadorequest GIYF aber trotzdem, überprüfen Sie hier
m0skit0
2
Links aus der offiziellen Dokumentation: Java SE Tutorial & Java Sprachspezifikation 9.2
LoganMzz

Antworten:

85

Hier spielen einige Probleme eine Rolle. Das erste ist das Problem, eine statische Methode zu deklarieren, ohne sie zu definieren. Das ist der Unterschied zwischen

public interface Foo {
  public static int bar();
}

und

public interface Foo {
  public static int bar() {
    ...
  }
}

Das erste ist aus den von Espo genannten Gründen unmöglich : Sie wissen nicht, welche implementierende Klasse die richtige Definition ist.

Java könnte Letzteres zulassen; und in der Tat, ab Java 8, tut es!

James A. Rosen
quelle
2
Ja - es ist idealogisch, nicht technisch. Der Grund, warum ich es gerne hätte, ist. dass man eine statische "Implementierungs" -Methode in einer Schnittstelle haben kann, die nur auf andere "Schnittstellen" -Methoden in der Schnittstelle verweist, die von implementierenden Klassen leicht wiederverwendet werden können. Aber man kann eine statische Klasse in einer Schnittstelle deklarieren , so dass sich dort Dinge wie MyInterface.Impl.doIt (MyInterface i, Object [] args) befinden können {...}
peterk
9
Seit Java 8 können Sie staticMethoden in einem definieren interface. Die Methoden müssen sein public.
Olivier Grégoire
4
@ OlivierGrégoire ... und sie werden nicht vererbt, was der Schlüssel ist.
William F. Jameson
1
Gute Antwort, obwohl "ungefähr gleichwertig" ROFLMAO xD ich es eher als "etwas ähnlich" ausgedrückt hätte.
Timo
44

Der Grund, warum Sie keine statische Methode in einer Schnittstelle haben können, liegt in der Art und Weise, wie Java statische Referenzen auflöst. Java wird sich nicht die Mühe machen, nach einer Instanz einer Klasse zu suchen, wenn versucht wird, eine statische Methode auszuführen. Dies liegt daran, dass statische Methoden nicht instanzabhängig sind und daher direkt aus der Klassendatei ausgeführt werden können. Da alle Methoden in einer Schnittstelle abstrakt sind, müsste die VM nach einer bestimmten Implementierung der Schnittstelle suchen, um den Code hinter der statischen Methode zu finden, damit sie ausgeführt werden kann. Dies widerspricht dann der Funktionsweise der statischen Methodenauflösung und würde zu einer Inkonsistenz in der Sprache führen.

Espo
quelle
3
Diese Erklärung erklärt das Problem nicht. Jede Schnittstelle hat eine eigene Klassendatei, sie könnte die statische Methode enthalten. Es wäre also keine Suche nach einer bestimmten Implementierung erforderlich.
Mnementh
Nicht jeder Schnittstellentyp in Java befindet sich in einer eigenen Datei und sollte auch nicht JLS entsprechen. Außerdem schreibt JLS nicht vor, dass Klassen immer in einem Dateisystem gespeichert werden müssen, ganz im Gegenteil.
Vlad Gudim
4
@Totophil: Schnittstellen dürfen sich nicht in einer einzelnen Java-Datei befinden, sondern haben nach dem Kompilieren eine eigene Klassendatei. Das habe ich geschrieben.
Mnementh
18

Ich werde Ihre Frage mit einem Beispiel beantworten. Angenommen, wir hätten eine Matheklasse mit einer statischen Methode hinzufügen. Sie würden diese Methode folgendermaßen aufrufen:

Math.add(2, 3);

Wenn Math eine Schnittstelle anstelle einer Klasse wäre, könnte es keine definierten Funktionen haben. Daher macht es keinen Sinn, etwas wie Math.add (2, 3) zu sagen.

Kyle Cronin
quelle
11

Der Grund liegt im Design-Prinzip, dass Java keine Mehrfachvererbung zulässt. Das Problem der Mehrfachvererbung kann anhand des folgenden Beispiels veranschaulicht werden:

public class A {
   public method x() {...}
}
public class B {
   public method x() {...}
}
public class C extends A, B { ... }

Was passiert nun, wenn Sie Cx () aufrufen? Wird Ax () oder Bx () ausgeführt? Jede Sprache mit Mehrfachvererbung muss dieses Problem lösen.

Schnittstellen ermöglichen in Java eine Art eingeschränkte Mehrfachvererbung. Um das oben genannte Problem zu vermeiden, dürfen sie keine Methoden haben. Wenn wir das gleiche Problem mit Schnittstellen und statischen Methoden betrachten:

public interface A {
   public static method x() {...}
}
public interface B {
   public static method x() {...}
}
public class C implements A, B { ... }

Gleiches Problem hier, was passiert, wenn Sie Cx () aufrufen?

Mnementh
quelle
Gibt es einen Grund für die Ablehnung? Ein erklärender Kommentar wäre schön.
Mnementh
Ich bin nicht der Downvoter, aber gilt dies nicht auch für nicht statische Methoden?
Nawfal
OK, hier sind zwei verschiedene Möglichkeiten. Eine Methode könnte implementiert oder nur deklariert werden. Ich habe verstanden, dass die statische Methode implementiert werden muss. In diesem Sinne stoße ich auf das in meiner Antwort dargestellte Problem. Wenn Sie das nicht tun, stoßen Sie auf das von Espo beschriebene Problem - und das habe ich nicht verstanden, weil ich davon ausgegangen bin, dass die statische Methode implementiert wird. Sie können aus diesem Grund auch keine statische abstrakte Methode deklarieren. Probieren Sie es aus, der Compiler wird sich beschweren.
Mnementh
Ok, vergiss den Implementierungsteil. Die Frage ist, warum wir nicht erklären können. Ja, der Compiler wird sich beschweren und warum ist das die Frage? worauf ich nicht glaube, dass du geantwortet hast.
Nawfal
1
Wie wäre es die Situation noch schlimmer sein als Schnittstelle mit Aenthalten int x(int z);und Schnittstelle Benthält string x(int x);? Was bedeutet die x(3)Schnittstelle C?
Supercat
7

Statische Methoden sind keine Instanzmethoden. Es gibt keinen Instanzkontext, daher ist es wenig sinnvoll, ihn über die Schnittstelle zu implementieren.

Ryan Farley
quelle
5

Mit Java8 können wir jetzt sogar statische Methoden in Interface definieren.

interface X {
    static void foo() {
       System.out.println("foo");
    }
}

class Y implements X {
    //...
}

public class Z {
   public static void main(String[] args) {
      X.foo();
      // Y.foo(); // won't compile because foo() is a Static Method of X and not Y
   }
}

Hinweis: Methoden in der Schnittstelle sind standardmäßig immer noch öffentlich abstrakt, wenn wir die Schlüsselwörter default / static nicht explizit verwenden, um sie zu Standardmethoden bzw. statischen Methoden zu machen.

Anandaraja_Srinivasan
quelle
4

Es ist eine sehr schöne und prägnante Antwort auf Ihre Frage hier . (Es kam mir so einfach vor, es zu erklären, dass ich es von hier aus verlinken möchte.)

Zarkonnen
quelle
Dies ist keine Antwort auf die Frage, bestenfalls sollte es ein Kommentar sein.
CubeJockey
3

Es scheint, dass die statische Methode in der Schnittstelle in Java 8 unterstützt wird. Meine Lösung besteht darin, sie nur in der inneren Klasse zu definieren.

interface Foo {
    // ...
    class fn {
        public static void func1(...) {
            // ...
        }
    }
}

Dieselbe Technik kann auch in Anmerkungen verwendet werden:

public @interface Foo {
    String value();

    class fn {
        public static String getValue(Object obj) {
            Foo foo = obj.getClass().getAnnotation(Foo.class);
            return foo == null ? null : foo.value();
        }
    }
}

Auf die innere Klasse sollte immer in Form von zugegriffen werden, Interface.fn...anstatt dass Class.fn...Sie dann mehrdeutige Probleme beseitigen können.

Xiè Jìléi
quelle
2

Für den Polymorphismus wird eine Schnittstelle verwendet, die für Objekte und nicht für Typen gilt. Daher ist es (wie bereits erwähnt) nicht sinnvoll, ein statisches Schnittstellenmitglied zu haben.

Rob Cooper
quelle
In einigen reflektierenden Kontexten scheint es jedoch fast sinnvoll zu sein
Cruncher
1

Java 8 hat die Welt verändert. Sie können statische Methoden in der Schnittstelle haben, aber es zwingt Sie, die Implementierung dafür bereitzustellen.

public interface StaticMethodInterface {
public static int testStaticMethod() {
    return 0;
}

/**
 * Illegal combination of modifiers for the interface method
 * testStaticMethod; only one of abstract, default, or static permitted
 * 
 * @param i
 * @return
 */
// public static abstract int testStaticMethod(float i);

default int testNonStaticMethod() {
    return 1;
}

/**
 * Without implementation.
 * 
 * @param i
 * @return
 */
int testNonStaticMethod(float i);

}}

Kumar Abhishek
quelle
0

Illegale Kombination von Modifikatoren: statisch und abstrakt

Wenn ein Mitglied einer Klasse als statisch deklariert ist, kann es mit seinem auf diese Klasse beschränkten Klassennamen verwendet werden, ohne ein Objekt zu erstellen.

Wenn ein Mitglied einer Klasse als abstrakt deklariert ist, müssen Sie die Klasse als abstrakt deklarieren und die Implementierung des abstrakten Mitglieds in seiner geerbten Klasse (Unterklasse) bereitstellen.

Sie müssen dem abstrakten Element einer Klasse in einer Unterklasse eine Implementierung bereitstellen, in der Sie das Verhalten der statischen Methode ändern, die ebenfalls als abstrakt deklariert ist und auf die Basisklasse beschränkt ist, was nicht korrekt ist

Sankar
quelle
Wie beantwortet dies die Frage? Das OP fragte nach der Schnittstelle, während Sie über die Klasse schrieben.
Glücklicher
0

Da statische Methoden nicht vererbt werden können. Es macht also keinen Sinn, es in die Benutzeroberfläche zu stellen. Interface ist im Grunde ein Vertrag, dem alle Abonnenten folgen müssen. Wenn Sie eine statische Methode in die Schnittstelle einfügen, werden die Abonnenten gezwungen, sie zu implementieren. Dies widerspricht nun der Tatsache, dass statische Methoden nicht vererbt werden können.

ip_x
quelle
statische Methoden werden immer vererbt, können aber nicht überschrieben werden.
Akki
0

Mit Java 8 können Schnittstellen jetzt statische Methoden haben.

Zum Beispiel hat Comparator eine statische naturalOrder () -Methode.

Die Anforderung, dass Schnittstellen keine Implementierungen haben dürfen, wurde ebenfalls gelockert. Schnittstellen können jetzt "Standard" -Methodenimplementierungen deklarieren, die mit einer Ausnahme wie normale Implementierungen sind: Wenn Sie sowohl eine Standardimplementierung von einer Schnittstelle als auch eine normale Implementierung von einer Oberklasse erben, hat die Implementierung der Oberklasse immer Vorrang.

Ishara
quelle
OH MEIN GOTT! Wir haben einen ernsthaften Programmierer (und mich, einen Kommentator), der eine 10 Jahre alte Frage beantwortet (und mich, einen Kommentar).
Mohamed Anees A
Ich habe das Datum nicht bemerkt :)
Ishara
Haha! Kein Problem!
Mohamed Anees A
-2

Vielleicht würde ein Codebeispiel helfen, ich werde C # verwenden, aber Sie sollten in der Lage sein, mitzumachen.

Stellen wir uns vor, wir hätten eine Schnittstelle namens IPayable

public interface IPayable
{
    public Pay(double amount);
}

Jetzt haben wir zwei konkrete Klassen, die diese Schnittstelle implementieren:

public class BusinessAccount : IPayable
{
    public void Pay(double amount)
    {
        //Logic
    }
}

public class CustomerAccount : IPayable
{
    public void Pay(double amount)
    {
        //Logic
    }
}

Stellen wir uns nun vor, wir hätten eine Sammlung verschiedener Konten. Dazu verwenden wir eine generische Liste vom Typ IPayable

List<IPayable> accountsToPay = new List<IPayable>();
accountsToPay.add(new CustomerAccount());
accountsToPay.add(new BusinessAccount());

Jetzt möchten wir 50,00 USD auf alle diese Konten zahlen:

foreach (IPayable account in accountsToPay)
{
    account.Pay(50.00);
}

Jetzt sehen Sie, wie unglaublich nützlich Schnittstellen sind.

Sie werden nur für instanziierte Objekte verwendet. Nicht für statische Klassen.

Wenn Sie die Zahlung statisch gemacht hätten, wäre es beim Durchlaufen der IPayable-Konten in AccountsToPay nicht möglich, herauszufinden, ob Pay on BusinessAcount oder CustomerAccount aufgerufen werden sollte.

FlySwat
quelle
Nur weil statische Methoden in DIESEM Beispiel keinen Sinn ergeben, bedeutet dies nicht, dass sie in JEDEM Beispiel keinen Sinn ergeben. In Ihrem Beispiel wäre dies ein realer Anwendungsfall, wenn die IPayable-Schnittstelle über die statische Methode "IncrementPayables" verfügt, mit der verfolgt wird, wie viele Verbindlichkeiten hinzugefügt wurden. Natürlich könnte man immer eine abstrakte Klasse verwenden, aber das haben Sie nicht angesprochen. Ihr Beispiel an sich untergräbt keine statischen Methoden in Schnittstellen.
Cruncher