Frage

Das Thema sagt schon das Meiste: Was ist der Grund dafür, dass statische Methoden nicht in einer Schnittstelle deklariert werden können?

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

Der obige Code gibt mir den folgenden Fehler (zumindest in Eclipse):„Ungültiger Modifikator für die Schnittstellenmethode ITest.test();Es sind nur öffentliche und abstrakte Beiträge zulässig.

War es hilfreich?

Lösung

Hier spielen einige Probleme eine Rolle.Das erste ist das Problem der Deklaration einer statischen Methode, 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 folgenden Gründen unmöglich Espo erwähnt:Sie wissen nicht, welche implementierende Klasse die richtige Definition ist.

Java könnte Letzteres zulassen;Und ab Java 8 ist dies tatsächlich der Fall!

Andere Tipps

Der Grund, warum Sie in einer Schnittstelle keine statische Methode haben können, liegt in der Art und Weise, wie Java statische Referenzen auflöst.Java macht sich nicht die Mühe, nach einer Instanz einer Klasse zu suchen, wenn es versucht, 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.

Ich beantworte Ihre Frage anhand eines Beispiels.Angenommen, wir hätten eine Math-Klasse mit einer statischen Methode hinzugefügt.Sie würden diese Methode folgendermaßen aufrufen:

Math.add(2, 3);

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

Der Grund liegt im Designprinzip, dass Java keine Mehrfachvererbung zulässt.Das Problem der Mehrfachvererbung lässt sich an folgendem Beispiel veranschaulichen:

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

Was passiert nun, wenn Sie C.x() aufrufen?Wird A.x() oder B.x() 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 uns das gleiche Problem mit Schnittstellen und statischen Methoden ansehen:

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

Hier das gleiche Problem. Was passiert, wenn Sie C.x() aufrufen?

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

Mit Java8 können wir jetzt sogar statische Methoden in der Schnittstelle 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
   }
}

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

Es gibt eine sehr schöne und prägnante Antwort auf Ihre Frage Hier.(Die Art und Weise, es zu erklären, kam mir so direkt vor, dass ich sie hier verlinken möchte.)

Es scheint, dass die statische Methode in der Schnittstelle möglicherweise unterstützt wird Java 8, Nun ja, meine Lösung besteht einfach darin, sie in der inneren Klasse zu definieren.

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

Die gleiche 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 der Form zugegriffen werden Interface.fn... anstatt Class.fn..., Dann können Sie das mehrdeutige Problem beseitigen.

Für den Polymorphismus wird eine Schnittstelle verwendet, die für Objekte und nicht für Typen gilt.Daher macht es (wie bereits erwähnt) keinen Sinn, ein statisches Interface-Member zu haben.

Java 8 hat die Welt verändert. Sie können statische Methoden in der Schnittstelle haben, aber es zwingt Sie, dafür eine Implementierung 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);

}

Unzulässige 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 dass ein Objekt erstellt wird.

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 Mitglied einer Klasse in einer Unterklasse eine Implementierung bereitstellen, in der Sie das Verhalten der statischen Methode ändern möchten, die ebenfalls als abstrakt deklariert ist und auf die Basisklasse beschränkt ist, was nicht korrekt ist

Da statische Methoden nicht vererbt werden können.Es hat also keinen Sinn, es in der Benutzeroberfläche zu platzieren.Bei der Schnittstelle handelt es sich grundsätzlich um einen Vertrag, den alle Abonnenten einhalten müssen.Das Platzieren einer statischen Methode in der Schnittstelle zwingt die Abonnenten, diese zu implementieren.was nun im Widerspruch zu der Tatsache steht, dass statische Methoden nicht vererbt werden können.

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

Comparator verfügt beispielsweise über eine statische naturalOrder()-Methode.

Auch die Anforderung, dass Schnittstellen keine Implementierungen haben dürfen, wurde gelockert.Schnittstellen können jetzt „Standard“-Methodenimplementierungen deklarieren, die mit einer Ausnahme normalen Implementierungen ähneln:Wenn Sie sowohl eine Standardimplementierung von einer Schnittstelle als auch eine normale Implementierung von einer Superklasse erben, hat die Implementierung der Superklasse immer Priorität.

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 $ 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 „Pay“ statisch gemacht hätten, gäbe es beim Durchlaufen der IPayables in „accountsToPay“ keine Möglichkeit herauszufinden, ob „Pay“ auf „BusinessAcount“ oder „CustomerAccount“ aufgerufen werden soll.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top