Warum kann ich keine statische Methode in einer Java-Schnittstelle definieren?

499

BEARBEITEN: Ab Java 8 sind statische Methoden in Schnittstellen zulässig.

Hier ist das Beispiel:

public interface IXMLizable<T>
{
  static T newInstanceFromXML(Element e);
  Element toXMLElement();
}

Das wird natürlich nicht funktionieren. Aber warum nicht?

Eines der möglichen Probleme wäre, was passiert, wenn Sie anrufen:

IXMLizable.newInstanceFromXML(e);

In diesem Fall sollte es meiner Meinung nach nur eine leere Methode (dh {}) aufrufen. Alle Unterklassen wären gezwungen, die statische Methode zu implementieren, sodass sie beim Aufrufen der statischen Methode in Ordnung wären. Warum ist das nicht möglich?

EDIT: Ich denke, ich suche nach einer Antwort, die tiefer geht als "weil Java so ist".

Gibt es einen bestimmten technologischen Grund, warum statische Methoden nicht überschrieben werden können? Das heißt, warum haben die Entwickler von Java beschlossen, Instanzmethoden überschreibbar, aber nicht statisch zu machen?

BEARBEITEN: Das Problem mit meinem Design ist, dass ich versuche, Schnittstellen zu verwenden, um eine Codierungskonvention durchzusetzen.

Das heißt, das Ziel der Schnittstelle ist zweierlei:

  1. Ich möchte, dass die IXMLizable-Schnittstelle es mir ermöglicht, Klassen, die sie implementieren, in XML-Elemente zu konvertieren (mit Polymorphismus funktioniert das einwandfrei).

  2. Wenn jemand eine neue Instanz einer Klasse erstellen möchte, die die IXMLizable-Schnittstelle implementiert, weiß er immer, dass es einen statischen Konstruktor newInstanceFromXML (Element e) gibt.

Gibt es eine andere Möglichkeit, dies sicherzustellen, als nur einen Kommentar in die Benutzeroberfläche einzufügen?

cdmckay
quelle
4
Sie müssen übrigens keine Methoden- (und Feld-) Definitionen mit public in interfaces überladen.
Tom Hawtin - Tackline
Hmm, scheint ein Duplikat von stackoverflow.com/questions/21817/… zu sein . Hatte das noch nie gesehen.
Michael Myers
1
Könnten Sie Code bereitstellen, wie Sie statische Schnittstellenmethoden verwenden möchten?
Pavel Feldman
43
Dies wird in Java 8 möglich sein: docs.oracle.com/javase/tutorial/java/IandI/…
Dakshang
1
@dakshang Ja, aber es macht nicht das, was das OP will.
user253751

Antworten:

518

Java 8 erlaubt statische Schnittstellenmethoden

Mit Java 8, Schnittstellen können statische Methoden haben. Sie können auch konkrete Instanzmethoden haben, jedoch keine Instanzfelder.

Hier gibt es wirklich zwei Fragen:

  1. Warum konnten Schnittstellen in schlechten alten Zeiten keine statischen Methoden enthalten?
  2. Warum können statische Methoden nicht überschrieben werden?

Statische Methoden in Schnittstellen

Es gab keinen starken technischen Grund, warum Schnittstellen in früheren Versionen keine statischen Methoden hatten. Dies wird durch das Poster einer doppelten Frage gut zusammengefasst. Statische Schnittstellenmethoden wurden anfangs als kleine Sprachänderung angesehen, und dann gab es einen offiziellen Vorschlag , sie in Java 7 hinzuzufügen, der jedoch später aufgrund unvorhergesehener Komplikationen eingestellt wurde.

Schließlich führte Java 8 statische Schnittstellenmethoden sowie überschreibbare Instanzmethoden mit einer Standardimplementierung ein. Sie können jedoch immer noch keine Instanzfelder haben. Diese Funktionen sind Teil der Unterstützung für Lambda-Ausdrücke. Weitere Informationen hierzu finden Sie in Teil H von JSR 335.

Statische Methoden überschreiben

Die Antwort auf die zweite Frage ist etwas komplizierter.

Statische Methoden können zur Kompilierungszeit aufgelöst werden. Dynamischer Versand ist beispielsweise bei Methoden sinnvoll, bei denen der Compiler den konkreten Typ des Objekts nicht bestimmen und daher die aufzurufende Methode nicht auflösen kann. Das Aufrufen einer statischen Methode erfordert jedoch eine Klasse. Da diese Klasse zur Kompilierungszeit statisch bekannt ist , ist ein dynamischer Versand nicht erforderlich .

Ein kleiner Hintergrund zur Funktionsweise von Instanzmethoden ist erforderlich, um zu verstehen, was hier vor sich geht. Ich bin mir sicher, dass die tatsächliche Implementierung ganz anders ist, aber lassen Sie mich meinen Begriff des Methodenversands erläutern, der das beobachtete Verhalten genau modelliert.

Stellen Sie sich vor, jede Klasse verfügt über eine Hash-Tabelle, die Methodensignaturen (Name und Parametertypen) einem tatsächlichen Codeabschnitt zuordnet, um die Methode zu implementieren. Wenn die virtuelle Maschine versucht, eine Methode für eine Instanz aufzurufen, fragt sie das Objekt nach ihrer Klasse ab und sucht die angeforderte Signatur in der Tabelle der Klasse. Wenn ein Methodenkörper gefunden wird, wird er aufgerufen. Andernfalls wird die übergeordnete Klasse der Klasse abgerufen und die Suche dort wiederholt. Dies wird fortgesetzt, bis die Methode gefunden wurde oder keine übergeordneten Klassen mehr vorhanden sind. Dies führt zu a NoSuchMethodError.

Wenn sowohl eine Oberklasse als auch eine Unterklasse einen Eintrag in ihren Tabellen für dieselbe Methodensignatur haben, wird zuerst die Version der Unterklasse gefunden und die Version der Oberklasse wird nie verwendet - dies ist eine "Überschreibung".

Angenommen, wir überspringen die Objektinstanz und beginnen einfach mit einer Unterklasse. Die Auflösung könnte wie oben beschrieben erfolgen und Ihnen eine Art "überschreibbare" statische Methode geben. Die Auflösung kann jedoch alle zur Kompilierungszeit erfolgen, da der Compiler von einer bekannten Klasse ausgeht und nicht bis zur Laufzeit wartet, um ein Objekt eines nicht angegebenen Typs nach seiner Klasse abzufragen. Es macht keinen Sinn, eine statische Methode zu "überschreiben", da man immer die Klasse angeben kann, die die gewünschte Version enthält.


Konstruktor "Schnittstellen"

Hier ist etwas mehr Material, um die letzte Bearbeitung der Frage zu behandeln.

Es hört sich so an, als ob Sie effektiv eine konstruktorähnliche Methode für jede Implementierung von festlegen möchten IXMLizable. Vergessen Sie für eine Minute, dies mit einer Schnittstelle durchzusetzen, und tun Sie so, als hätten Sie einige Klassen, die diese Anforderung erfüllen. Wie würden Sie es verwenden?

class Foo implements IXMLizable<Foo> {
  public static Foo newInstanceFromXML(Element e) { ... }
}

Foo obj = Foo.newInstanceFromXML(e);

Da Sie Foobeim "Erstellen" des neuen Objekts den konkreten Typ explizit benennen müssen , kann der Compiler überprüfen, ob er tatsächlich über die erforderliche Factory-Methode verfügt. Und wenn nicht, was dann? Wenn ich eine implementieren kann IXMLizable, der der "Konstruktor" fehlt, und ich eine Instanz erstelle und sie an Ihren Code übergebe, ist sie eine IXMLizablemit allen erforderlichen Schnittstellen.

Die Konstruktion ist Teil der Implementierung, nicht der Schnittstelle. Jeder Code, der erfolgreich mit der Schnittstelle arbeitet, kümmert sich nicht um den Konstruktor. Jeder Code, der sich um den Konstruktor kümmert, muss den konkreten Typ sowieso kennen, und die Schnittstelle kann ignoriert werden.

erickson
quelle
Guter Anruf bei Project Coin. mail.openjdk.java.net/pipermail/coin-dev/2009-March/000117.html
Michael Myers
12
Könnte Grund für # 1 Mehrfachvererbung sein? Da wir von mehreren Schnittstellen erben können, wenn zwei Schnittstellen dieselbe statische Methodensignatur enthielten und dann eine Klasse beide implementierte und diese Methode aufrief, könnten die Dinge auf eine Weise kompliziert werden, die Java-Sprachentwickler vermeiden wollten, indem sie die Vererbung mehrerer Klassen nicht zulassen der erste Ort. Dasselbe Argument könnte offensichtlich für die Schnittstelle angeführt werden, die überhaupt keine Methodendefinition zulässt.
shrini1000
1
@ shrini1000 - Nein, statische Methoden werden zur Kompilierungszeit aufgelöst. Die Mehrdeutigkeit kann genauso behandelt werden wie mit Konstanten: mit einem Compilerfehler. Der Vorschlag unter Project Coin wurde jedoch unter Berufung auf einige unvorhergesehene Schwierigkeiten abgelehnt. Ich bin mir nicht sicher, was sie waren, aber ich glaube nicht, dass es in diese Richtung ging.
Erickson
1
@ tgm1024 Ja, der Abschnitt "Konstruktor-Schnittstellen" erklärt, warum es nicht sinnvoll ist, polymorphes Verhalten über einen zur Kompilierungszeit bekannten Typ aufzurufen. Wie würden Sie sich RESET()auf eine bestimmte Klasse berufen? Du würdest schreiben SomeClass.RESET(). Sie benötigen also keine Schnittstelle, um diese API zu beschreiben. es ist statisch. Schnittstellen werden verwendet, wenn Sie den konkreten Typ beim Kompilieren nicht kennen. Dies ist bei einer statischen Methode nie der Fall.
erickson
2
"Die Konstruktion ist Teil der Implementierung, nicht der Schnittstelle. Jeder Code, der erfolgreich mit der Schnittstelle arbeitet, kümmert sich nicht um den Konstruktor." - Das ist eindeutig nicht wahr. In anderen Sprachen (z. B. Swift) kann ich neue Instanzen erstellen, Tohne dies Tstatisch zu wissen , da ich in einer Schnittstelle verspreche, dass zur Laufzeit ein bestimmter Konstruktor (oder eine bestimmte statische Methode) vorhanden sein wird. Die Tatsache, dass die Generierung in Java nicht spezifizierbar ist, bedeutet nicht, dass dies keine sinnvolle Sache ist.
Raphael
48

Dies wurde bereits gestellt und beantwortet, hier

Um meine Antwort zu duplizieren:

Es macht nie Sinn, eine statische Methode in einer Schnittstelle zu deklarieren. Sie können nicht mit dem normalen Aufruf MyInterface.staticMethod () ausgeführt werden. Wenn Sie sie durch Angabe der implementierenden Klasse MyImplementor.staticMethod () aufrufen, müssen Sie die tatsächliche Klasse kennen, sodass es unerheblich ist, ob die Schnittstelle sie enthält oder nicht.

Noch wichtiger ist, dass statische Methoden niemals überschrieben werden. Wenn Sie dies versuchen:

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

Die Regeln für statisch besagen, dass die im deklarierten Var-Typ definierte Methode ausgeführt werden muss. Da dies eine Schnittstelle ist, ist dies unmöglich.

Der Grund, warum Sie "result = MyInterface.staticMethod ()" nicht ausführen können, ist, dass die in MyInterface definierte Version der Methode ausgeführt werden muss. In MyInterface kann jedoch keine Version definiert werden, da es sich um eine Schnittstelle handelt. Es hat per Definition keinen Code.

Während man sagen kann, dass dies "weil Java es so macht" bedeutet, ist die Entscheidung in Wirklichkeit eine logische Folge anderer Entwurfsentscheidungen, die ebenfalls aus sehr guten Gründen getroffen wurden.

DJClayworth
quelle
14
Wenn Sie <T erweitert MyInterface> als generischen Typparameter verwenden, wäre es schön, über die Schnittstelle zu garantieren, dass T .doSomething () kann.
Chris Betti
4
Obwohl ich die Argumente verstehe, stimme ich @Chris_Betti zu (auch für nicht generische Typen): Es wäre schön, wenn die Codestruktur sicherstellen würde, dass einige Klassen eine bestimmte statische API implementieren . Vielleicht ist es möglich, ein anderes Konzept zu verwenden ...
Juh_
@Juh_, ..... oder ein neues Schlüsselwort, falls unbedingt erforderlich. Ich glaube, es staticist sowieso ein mieser Begriff in Sprachen und wurde zu weit gedehnt. Es ist also schon lückenhaft, es für sich zu haben. Siehe mein Beispiel oben stackoverflow.com/questions/512877/… {Achselzucken}.
3
Dies scheint nicht wahr zu sein: "Es hat nie Sinn, eine statische Methode in einer Schnittstelle zu deklarieren." Wenn ich eine Sammlung von Klassen habe, die mir ohne Instanziierung einige Informationen bieten könnten, aber ich würde eine gemeinsame Schnittstelle benötigen, um diese statischen Informationen auf Klassenebene einzufügen (dh eine Schnittstelle mit einer überschreibbaren statischen Methode), dann ist dies eine gültige Verwendung . Denken Sie an Reflection ++, wo Sie Metainformationen über Klasseneigenschaften erfassen können, ohne mit Attributen, Reflection usw.
Jason
1
"Es hat nie Sinn, eine statische Methode in einer Schnittstelle zu deklarieren." Dies ist nicht wahr: Stellen Sie sich vor, Ihr System verfügt über einen Standardklassenauflöser. Wenn festgestellt wird, dass Sie die Methode ContainerInjectionInterce :: create (Container $ container) implementieren, wird das Objekt beispielsweise mit dieser Funktion erstellt.
user3790897
37

Normalerweise erfolgt dies nach einem Factory-Muster

public interface IXMLizableFactory<T extends IXMLizable> {
  public T newInstanceFromXML(Element e);
}

public interface IXMLizable {
  public Element toXMLElement();
}
Peter Lawrey
quelle
7
+1 Ein Factory-Muster klingt nach einer Lösung für das Problem. (wenn auch nicht auf die Frage)
pvgoddijn
Kann mir jemand sagen, was es bedeutet, <T erweitert IXMLizable> hier zu setzen. Ich bin neu in Java. Was macht es?
Nuwan Harshakumara Piyarathna
1
@NuwanHarshakumaraPiyarathna T muss eine Klasse sein, die IXMLizable erweitert. Schauen Sie sich Java-Generika an, um besser zu verstehen, was dies bedeutet
Adrian
37

Mit dem Aufkommen von Java 8 ist es jetzt möglich, Standard- und statische Methoden in die Schnittstelle zu schreiben . docs.oracle/staticMethod

Zum Beispiel:

public interface Arithmetic {

    public int add(int a, int b);

    public static int multiply(int a, int b) {
        return a * b;
    }
}
public class ArithmaticImplementation implements Arithmetic {

    @Override
    public int add(int a, int b) {
        return a + b;
    }

    public static void main(String[] args) {
        int result = Arithmetic.multiply(2, 3);
        System.out.println(result);
    }
}

Ergebnis : 6

TIPP: Das Aufrufen einer statischen Schnittstellenmethode muss von keiner Klasse implementiert werden. Dies geschieht sicherlich, weil für statische Methoden an Schnittstellen dieselben Regeln für statische Methoden in Oberklassen gelten.

Schurkenjunge
quelle
Dies ist ein perfektes Beispiel für diese Frage.
21

Weil statische Methoden in Unterklassen nicht überschrieben werden können und daher nicht abstrakt sein können. Und alle Methoden in einer Schnittstelle sind de facto abstrakt.

Michael Myers
quelle
2
Sie können jeden Typ jederzeit zwingen, statische Schnittstellenmethoden zu implementieren. Typklassen, jemand?
MichaelGG
16
Treten Sie aus sich heraus und beantworten Sie die Frage: Warum können statische Methoden nicht überschrieben werden? Wenn statische Methoden überschrieben werden könnten, wie würde es aussehen? Was könntest du mit ihnen machen? Diese Antwort lautet im Grunde: "Sie können nicht, weil Sie nicht können."
Erickson
10

Warum kann ich keine statische Methode in einer Java-Schnittstelle definieren?

Eigentlich kann man das in Java 8.

Gemäß Java- Dokument :

Eine statische Methode ist eine Methode, die der Klasse zugeordnet ist, in der sie definiert ist, und nicht einem Objekt. Jede Instanz der Klasse teilt ihre statischen Methoden

In Java 8 kann eine Schnittstelle Standardmethoden und statische Methoden haben . Dies erleichtert uns die Organisation von Hilfsmethoden in unseren Bibliotheken. Wir können statische Methoden, die für eine Schnittstelle spezifisch sind, in derselben Schnittstelle und nicht in einer separaten Klasse aufbewahren.

Beispiel für eine Standardmethode:

list.sort(ordering);

anstatt

Collections.sort(list, ordering);

Beispiel einer statischen Methode (aus dem Dokument selbst):

public interface TimeClient {
    // ...
    static public ZoneId getZoneId (String zoneString) {
        try {
            return ZoneId.of(zoneString);
        } catch (DateTimeException e) {
            System.err.println("Invalid time zone: " + zoneString +
                "; using default time zone instead.");
            return ZoneId.systemDefault();
        }
    }

    default public ZonedDateTime getZonedDateTime(String zoneString) {
        return ZonedDateTime.of(getLocalDateTime(), getZoneId(zoneString));
    }    
}
akhil_mittal
quelle
6

Schnittstellen befassen sich mit Polymorphismus, der von Natur aus an Objektinstanzen und nicht an Klassen gebunden ist. Daher ist statisch im Kontext einer Schnittstelle nicht sinnvoll.

cliff.meyers
quelle
Klare, prägnante Logik. Gut ausgedrückt.
Oke Uwechue
6

Erstens sind alle Sprachentscheidungen Entscheidungen der Sprachschöpfer. In der Welt des Software-Engineerings oder der Sprachdefinition oder des Schreibens von Compilern / Interpreten gibt es nichts, was besagt, dass eine statische Methode nicht Teil einer Schnittstelle sein kann. Ich habe ein paar Sprachen erstellt und Compiler für sie geschrieben - alles setzt sich nur hin und definiert eine sinnvolle Semantik. Ich würde argumentieren, dass die Semantik einer statischen Methode in einer Schnittstelle bemerkenswert klar ist - selbst wenn der Compiler die Auflösung der Methode auf die Laufzeit verschieben muss.

Zweitens bedeutet die Tatsache, dass wir überhaupt statische Methoden verwenden, dass es einen gültigen Grund für ein Schnittstellenmuster gibt, das statische Methoden enthält. Ich kann für keinen von Ihnen sprechen, aber ich verwende regelmäßig statische Methoden.

Die wahrscheinlichste richtige Antwort ist, dass zum Zeitpunkt der Definition der Sprache kein Bedarf an statischen Methoden in Schnittstellen bestand. Java ist im Laufe der Jahre stark gewachsen und dies ist ein Punkt, der anscheinend ein gewisses Interesse geweckt hat. Dass es für Java 7 geprüft wurde, zeigt, dass es auf ein Interesse gestiegen ist, das zu einer Sprachänderung führen könnte. Zum einen bin ich froh, wenn ich kein Objekt mehr instanziieren muss, nur damit ich meine nicht statische Getter-Methode aufrufen kann, um auf eine statische Variable in einer Unterklasseninstanz zuzugreifen ...

großes Mädchen
quelle
5

Statische Methoden sind nicht virtuell wie Instanzmethoden, daher haben die Java-Designer vermutlich entschieden, dass sie nicht in Schnittstellen verwendet werden sollen.

Sie können jedoch Klassen mit statischen Methoden in Schnittstellen einfügen. Das könntest du versuchen!

public interface Test {
    static class Inner {
        public static Object get() {
            return 0;
        }
    }
}
Adrian Pronk
quelle
5
  • "Gibt es einen bestimmten Grund, warum statische Methoden nicht überschrieben werden können?"

Lassen Sie mich diese Frage für Sie umformulieren, indem Sie die Definitionen ausfüllen.

  • "Gibt es einen bestimmten Grund, warum zur Kompilierungszeit aufgelöste Methoden zur Laufzeit nicht aufgelöst werden können?"

Oder, um es vollständiger auszudrücken: Wenn ich eine Methode ohne Instanz aufrufen möchte, aber die Klasse kenne, wie kann ich sie basierend auf der Instanz auflösen lassen, die ich nicht habe?

Darron
quelle
3

In mehreren Antworten wurden die Probleme mit dem Konzept überschreibbarer statischer Methoden erörtert. Manchmal stößt man jedoch auf ein Muster, bei dem es so aussieht, als ob Sie genau das verwenden möchten.

Zum Beispiel arbeite ich mit einer objektrelationalen Ebene, die Wertobjekte enthält, aber auch Befehle zum Bearbeiten der Wertobjekte. Aus verschiedenen Gründen muss jede Wertobjektklasse einige statische Methoden definieren, mit denen das Framework die Befehlsinstanz finden kann. So erstellen Sie beispielsweise eine Person:

cmd = createCmd(Person.getCreateCmdId());
Person p = cmd.execute();

und um eine Person nach ID zu laden, würden Sie tun

cmd = createCmd(Person.getGetCmdId());
cmd.set(ID, id);
Person p = cmd.execute();

Dies ist ziemlich praktisch, hat jedoch seine Probleme; Insbesondere das Vorhandensein der statischen Methoden kann in der Schnittstelle nicht erzwungen werden. Eine überschreibbare statische Methode in der Schnittstelle wäre genau das, was wir brauchen würden, wenn sie nur irgendwie funktionieren könnte.

EJBs lösen dieses Problem durch eine Home-Schnittstelle. Jedes Objekt weiß, wie es sein Home findet, und das Home enthält die "statischen" Methoden. Auf diese Weise können die "statischen" Methoden nach Bedarf überschrieben werden, und Sie überladen die normale (als "Remote" bezeichnete) Schnittstelle nicht mit Methoden, die nicht für eine Instanz Ihrer Bean gelten. Lassen Sie einfach die normale Schnittstelle eine "getHome ()" - Methode angeben. Gibt eine Instanz des Home-Objekts zurück (das vermutlich ein Singleton sein könnte), und der Aufrufer kann Vorgänge ausführen, die alle Person-Objekte betreffen.

Mr. Shiny und New 安 宇
quelle
3

Kommentieren EDIT: As of Java 8, static methods are now allowed in interfaces.

Es ist richtig, statische Methoden, da Java 8 in Schnittstellen zulässig ist, aber Ihr Beispiel funktioniert immer noch nicht. Sie können nicht einfach eine statische Methode definieren: Sie müssen sie implementieren, sonst wird ein Kompilierungsfehler angezeigt.

Flavio
quelle
2

Ohne Generika sind statische Schnittstellen nutzlos, da alle statischen Methodenaufrufe zur Kompilierungszeit aufgelöst werden. Es gibt also keine wirkliche Verwendung für sie.

Mit Generika können sie verwendet werden - mit oder ohne Standardimplementierung. Offensichtlich müsste es Überschreibungen geben und so weiter. Ich vermute jedoch, dass eine solche Verwendung nicht sehr OO war (wie die anderen Antworten deutlich zeigen) und daher nicht als die Mühe wert angesehen wurde, die sie für eine sinnvolle Implementierung benötigen würden.

MichaelGG
quelle
1
Was haben Generika damit zu tun? Eine statische Methode auf einer Schnittstelle wäre immer noch nicht ausführbar.
DJClayworth
Erstens wäre das eine Umsetzungsentscheidung. Aber ich vermute, er möchte keine statischen Methoden auf einer Schnittstelle aufrufen (er könnte einfach eine Klasse verwenden). Aber stattdessen möchte etwas wie eine Typklasse oder so etwas über Typparameter. In der Tat zeigt seine neueste Ausgabe dies noch deutlicher.
MichaelGG
2
Why can't I define a static method in a Java interface?

Alle Methoden in einer Schnittstelle sind explizit abstrakt und können daher nicht als statisch definiert werden, da statische Methoden nicht abstrakt sein können.

Aniket Thakur
quelle
1

Eine Schnittstelle kann niemals statisch dereferenziert werden, z ISomething.member. Eine Schnittstelle wird immer über eine Variable dereferenziert, die sich auf eine Instanz einer Unterklasse der Schnittstelle bezieht. Somit kann eine Schnittstellenreferenz ohne eine Instanz ihrer Unterklasse niemals wissen, auf welche Unterklasse sie verweist.

Daher wäre die nächste Annäherung an eine statische Methode in einer Schnittstelle eine nicht statische Methode, die "dies" ignoriert, dh nicht auf nicht statische Mitglieder der Instanz zugreift. Bei der Abstraktion auf niedriger Ebene ist jede nicht statische Methode (nach dem Nachschlagen in einer beliebigen vtable) wirklich nur eine Funktion mit Klassenbereich, die "dies" als impliziten formalen Parameter verwendet. Sehen Sie Scalas Singleton-Objekt und die Interoperabilität mit Java als Beweis für dieses Konzept. Und so ist jede statische Methode eine Funktion mit Klassenbereich, die keinen "this" -Parameter akzeptiert. Daher kann normalerweise eine statische Methode statisch aufgerufen werden, aber wie bereits erwähnt, hat eine Schnittstelle keine Implementierung (ist abstrakt).

Um einer statischen Methode in einer Schnittstelle am nächsten zu kommen, müssen Sie eine nicht statische Methode verwenden und dann auf keines der nicht statischen Instanzmitglieder zugreifen. Es würde keinen anderen Leistungsvorteil auf andere Weise geben, da es keine Möglichkeit gibt, (zur Kompilierungszeit) a statisch zu verknüpfen ISomething.member(). Der einzige Vorteil einer statischen Methode in einer Schnittstelle besteht darin, dass sie kein implizites "Dies" eingibt (dh ignoriert) und somit den Zugriff auf nicht statische Instanzmitglieder nicht zulässt. Dies würde implizit erklären, dass die Funktion, die nicht auf "dies" zugreift, unverfälscht und in Bezug auf ihre enthaltende Klasse nicht einmal schreibgeschützt ist. Eine Deklaration von "statisch" in einer Schnittstelle ISomethingwürde aber auch Leute verwirren, die versucht haben, darauf zuzugreifenISomething.member()Dies würde einen Compilerfehler verursachen. Ich nehme an, wenn der Compilerfehler ausreichend erklärend wäre, wäre es besser, als zu versuchen, die Leute über die Verwendung einer nicht statischen Methode aufzuklären, um das zu erreichen, was sie wollen (anscheinend meistens Factory-Methoden), wie wir es hier tun (und dies wurde für 3 wiederholt Fragen und Antworten auf dieser Website), daher ist es offensichtlich ein Problem, das für viele Menschen nicht intuitiv ist. Ich musste eine Weile darüber nachdenken, um das richtige Verständnis zu bekommen.

Der Weg, um ein veränderbares statisches Feld in einer Schnittstelle zu erhalten, besteht darin, nicht statische Getter- und Setter-Methoden in einer Schnittstelle zu verwenden, um auf das statische Feld in der Unterklasse zuzugreifen. Nebenbei bemerkt, scheinbar unveränderliche Statik kann in einer Java-Schnittstelle mit deklariert werden static final.

Shelby Moore III
quelle
0

Schnittstellen bieten nur eine Liste der Dinge, die eine Klasse bereitstellen wird, nicht eine tatsächliche Implementierung dieser Dinge, wie es Ihr statisches Element ist.

Wenn Sie Statik wünschen, verwenden Sie eine abstrakte Klasse und erben Sie sie. Andernfalls entfernen Sie die Statik.

Ich hoffe, das hilft!

Samoz
quelle
2
Theoretisch könnten Sie eine Schnittstelle definieren, die ein statisches Verhalten enthält, dh "Implementierungen dieser Schnittstelle haben eine statische Methode foo () mit dieser Signatur", und die Implementierung der spezifischen Klasse überlassen. Ich bin auf Situationen gestoßen, in denen dieses Verhalten nützlich wäre.
Rob
0

Sie können keine statischen Methoden in einer Schnittstelle definieren, da statische Methoden zu einer Klasse gehören, die nicht zu einer Instanz einer Klasse gehört, und Schnittstellen keine Klassen sind. Lesen Sie hier mehr.

Wenn Sie möchten, können Sie dies jedoch tun:

public class A {
  public static void methodX() {
  }
}

public class B extends A {
  public static void methodX() {
  }
}

In diesem Fall haben Sie zwei Klassen mit zwei unterschiedlichen statischen Methoden namens methodX ().

Handerson
quelle
0

Angenommen, Sie könnten es tun. Betrachten Sie dieses Beispiel:

interface Iface {
  public static void thisIsTheMethod();
}

class A implements Iface {

  public static void thisIsTheMethod(){
    system.out.print("I'm class A");
  }

}

class B extends Class A {

  public static void thisIsTheMethod(){
    System.out.print("I'm class B");
  } 
}

SomeClass {

  void doStuff(Iface face) {
    IFace.thisIsTheMethod();
    // now what would/could/should happen here.
  }

}
pvgoddijn
quelle
1
Es würde "Ich bin Klasse A" drucken. Wenn Sie jedoch tippen A.thisIsTheMethod(), wird "Ich bin Klasse B" ausgegeben.
CDMckay
Aber wie würden Sie (oder der Compiler) wissen, welche Methode aufgerufen werden soll, wenn Sie die Methoden auf der Schnittstelle aufrufen? (rember es kann mehr Klassen geben, die Iface
pvgoddijn
Entschuldigung, ich wollte sagen: Wenn Sie jedoch tippen B.thisIsTheMethod(), wird "Ich bin Klasse B" ausgegeben.
CDMckay
Ich sagte IFace.thisIsTHeMethod absichtlich, weil darin das Problem liegt. Es wäre nicht möglich, es auf der Schnittstelle ohne undefiniertes Verhalten aufzurufen (obwohl es darauf deklariert ist)
pvgoddijn
0

Etwas, das implementiert werden könnte, ist eine statische Schnittstelle (anstelle einer statischen Methode in einer Schnittstelle). Alle Klassen, die eine bestimmte statische Schnittstelle implementieren, sollten die entsprechenden statischen Methoden implementieren. Sie können statische Schnittstelle SI von jedem Class Clazz mit erhalten

SI si = clazz.getStatic(SI.class); // null if clazz doesn't implement SI
// alternatively if the class is known at compile time
SI si = Someclass.static.SI; // either compiler errror or not null

dann kannst du anrufen si.method(params). Dies wäre nützlich (zum Beispiel für das Factory-Design-Muster), da Sie die Implementierung von statischen SI-Methoden aus einer unbekannten Klasse zur Kompilierungszeit abrufen (oder deren Implementierung überprüfen) können! Ein dynamischer Versand ist erforderlich, und Sie können die statischen Methoden (wenn nicht endgültig) einer Klasse überschreiben, indem Sie sie erweitern (wenn sie über die statische Schnittstelle aufgerufen werden). Offensichtlich können diese Methoden nur auf statische Variablen ihrer Klasse zugreifen.

Christophe Bouchon
quelle
0

Obwohl mir klar ist, dass Java 8 dieses Problem behebt, dachte ich, ich würde mich auf ein Szenario einlassen, an dem ich gerade arbeite (an die Verwendung von Java 7 gebunden), in dem es hilfreich wäre, statische Methoden in einer Schnittstelle anzugeben.

Ich habe mehrere Aufzählungsdefinitionen, in denen ich die Felder "id" und "displayName" sowie Hilfsmethoden definiert habe, die die Werte aus verschiedenen Gründen auswerten. Durch die Implementierung einer Schnittstelle kann ich sicherstellen, dass die Getter-Methoden vorhanden sind, nicht jedoch die statischen Hilfsmethoden. Da es sich um eine Aufzählung handelt, gibt es wirklich keine saubere Möglichkeit, die Hilfsmethoden in eine geerbte abstrakte Klasse oder ähnliches zu verlagern. Daher müssen die Methoden in der Aufzählung selbst definiert werden. Auch weil es sich um eine Aufzählung handelt, würden Sie es niemals als instanziiertes Objekt übergeben und als Schnittstellentyp behandeln können, aber die Möglichkeit, die Existenz der statischen Hilfsmethoden über eine Schnittstelle zu verlangen, gefällt mir es wird in Java 8 unterstützt.

Hier ist ein Code, der meinen Standpunkt veranschaulicht.

Schnittstellendefinition:

public interface IGenericEnum <T extends Enum<T>> {
    String getId();
    String getDisplayName();
    //If I was using Java 8 static helper methods would go here
}

Beispiel für eine Aufzählungsdefinition:

public enum ExecutionModeType implements IGenericEnum<ExecutionModeType> {
    STANDARD ("Standard", "Standard Mode"),
    DEBUG ("Debug", "Debug Mode");

    String id;
    String displayName;

    //Getter methods
    public String getId() {
        return id;
    }

    public String getDisplayName() {
        return displayName;
    }

    //Constructor
    private ExecutionModeType(String id, String displayName) {
        this.id = id;
        this.displayName = displayName;
    }

    //Helper methods - not enforced by Interface
    public static boolean isValidId(String id) {
        return GenericEnumUtility.isValidId(ExecutionModeType.class, id);
    }

    public static String printIdOptions(String delimiter){
        return GenericEnumUtility.printIdOptions(ExecutionModeType.class, delimiter);
    }

    public static String[] getIdArray(){
        return GenericEnumUtility.getIdArray(ExecutionModeType.class);
    }

    public static ExecutionModeType getById(String id) throws NoSuchObjectException {
        return GenericEnumUtility.getById(ExecutionModeType.class, id);
    }
}

Allgemeine Definition des Enum-Dienstprogramms:

public class GenericEnumUtility {
    public static <T extends Enum<T> & IGenericEnum<T>> boolean isValidId(Class<T> enumType, String id) {       
        for(IGenericEnum<T> enumOption : enumType.getEnumConstants()) {
            if(enumOption.getId().equals(id)) {
                return true;
            }
        }

        return false;
    }

    public static <T extends Enum<T> & IGenericEnum<T>> String printIdOptions(Class<T> enumType, String delimiter){
        String ret = "";
        delimiter = delimiter == null ? " " : delimiter;

        int i = 0;
        for(IGenericEnum<T> enumOption : enumType.getEnumConstants()) {
            if(i == 0) {
                ret = enumOption.getId();
            } else {
                ret += delimiter + enumOption.getId();
            }           
            i++;
        }

        return ret;
    }

    public static <T extends Enum<T> & IGenericEnum<T>> String[] getIdArray(Class<T> enumType){
        List<String> idValues = new ArrayList<String>();

        for(IGenericEnum<T> enumOption : enumType.getEnumConstants()) {
            idValues.add(enumOption.getId());
        }

        return idValues.toArray(new String[idValues.size()]);
    }

    @SuppressWarnings("unchecked")
    public static <T extends Enum<T> & IGenericEnum<T>> T getById(Class<T> enumType, String id) throws NoSuchObjectException {
        id = id == null ? "" : id;
        for(IGenericEnum<T> enumOption : enumType.getEnumConstants()) {
            if(id.equals(enumOption.getId())) {
                return (T)enumOption;
            }
        }

        throw new NoSuchObjectException(String.format("ERROR: \"%s\" is not a valid ID. Valid IDs are: %s.", id, printIdOptions(enumType, " , ")));
    }
}
Ryan
quelle
0

Nehmen wir an, statische Methoden waren in Schnittstellen zulässig: * Sie würden alle implementierenden Klassen zwingen, diese Methode zu deklarieren. * Schnittstellen werden normalerweise über Objekte verwendet, daher sind die nicht wirksamen Methoden die nicht statischen. * Jede Klasse, die eine bestimmte Schnittstelle kennt, kann ihre statischen Methoden aufrufen. Daher würde die statische Methode einer implementierenden Klasse darunter aufgerufen, aber die Aufruferklasse weiß nicht, welche. Woher weiß ich das? Es gibt keine Instanziierung, um das zu erraten!

Es wurde angenommen, dass Schnittstellen beim Arbeiten mit Objekten verwendet werden. Auf diese Weise wird ein Objekt aus einer bestimmten Klasse instanziiert, sodass diese letzte Angelegenheit gelöst wird. Die aufrufende Klasse muss nicht wissen, um welche bestimmte Klasse es sich handelt, da die Instanziierung von einer dritten Klasse durchgeführt werden kann. Die aufrufende Klasse kennt also nur die Schnittstelle.

Wenn dies auf statische Methoden erweitert werden soll, sollten wir die Möglichkeit haben, zuvor eine implementierende Klasse anzugeben und dann einen Verweis auf die aufrufende Klasse zu übergeben. Dies könnte die Klasse über die statischen Methoden in der Schnittstelle verwenden. Aber was ist der Unterschied zwischen dieser Referenz und einem Objekt? Wir brauchen nur ein Objekt, das die Klasse darstellt. Jetzt repräsentiert das Objekt die alte Klasse und könnte eine neue Schnittstelle implementieren, die die alten statischen Methoden enthält - diese sind jetzt nicht statisch.

Zu diesem Zweck dienen Metaklassen. Sie können die Klasse Class of Java ausprobieren. Das Problem ist jedoch, dass Java dafür nicht flexibel genug ist. Sie können keine Methode im Klassenobjekt einer Schnittstelle deklarieren.

Dies ist ein Meta-Problem - wenn Sie Arsch tun müssen

..blah blah

Auf jeden Fall haben Sie eine einfache Problemumgehung: Sie machen die Methode mit derselben Logik nicht statisch. Dann müssten Sie jedoch zuerst ein Objekt erstellen, um die Methode aufzurufen.

Beibichunai
quelle
0

Um dies zu lösen: Fehler: fehlender Methodenkörper oder deklarieren Sie den abstrakten statischen void main (String [] args);

interface I
{
    int x=20;
    void getValue();
    static void main(String[] args){};//Put curly braces 
}
class InterDemo implements I
{
    public void getValue()
    {
    System.out.println(x);
    }
    public static void main(String[] args)
    {
    InterDemo i=new InterDemo();
    i.getValue();   
    }

}

Ausgabe: 20

Jetzt können wir die statische Methode in der Schnittstelle verwenden

Aashish Pawar
quelle
1
Das ist aber nutzlos. Das Definieren einer statischen Methode auf einer Schnittstelle erzwingt keine weiteren Definitionen in Klassen, die eine solche Schnittstelle implementieren. Wenn Sie die statische Methode nur vollständig von der Schnittstelle I entfernen, wird Ihr Code trotzdem problemlos kompiliert und ausgeführt. Mit anderen Worten, Sie überschreiben NICHT die Hauptmethode der I-Schnittstelle in der InterDemo-Klasse, sondern erstellen lediglich eine neue Methode mit derselben Signatur.
Fran Marzoa
-2

Ich denke, Java hat keine statischen Schnittstellenmethoden, weil Sie sie nicht benötigen. Sie denken vielleicht, dass Sie es tun, aber ... Wie würden Sie sie verwenden? Wenn du sie gerne so nennen willst

MyImplClass.myMethod()

dann müssen Sie es nicht in der Schnittstelle deklarieren. Wenn du sie gerne so nennen willst

myInstance.myMethod()

dann sollte es nicht statisch sein. Wenn Sie tatsächlich den ersten Weg verwenden, aber nur jede Implementierung mit einer solchen statischen Methode erzwingen möchten, handelt es sich tatsächlich um eine Codierungskonvention, nicht um einen Vertrag zwischen einer Instanz, die eine Schnittstelle implementiert, und einem aufrufenden Code.

Mit Schnittstellen können Sie einen Vertrag zwischen einer Klasseninstanz definieren, die die Schnittstelle implementiert, und den aufrufenden Code. Und Java hilft Ihnen sicherzustellen, dass dieser Vertrag nicht verletzt wird. Sie können sich also darauf verlassen und sich keine Sorgen machen, welche Klasse diesen Vertrag umsetzt. Nur "jemand, der einen Vertrag unterschrieben hat" ist genug. Bei statischen Schnittstellen Ihr Code

MyImplClass.myMethod()

beruht nicht auf der Tatsache, dass jede Schnittstellenimplementierung über diese Methode verfügt, sodass Sie kein Java benötigen, um sicherzugehen.

Pavel Feldman
quelle
-5

Was ist die Notwendigkeit der statischen Methode in der Schnittstelle, statische Methoden werden grundsätzlich verwendet, wenn Sie keine Instanz des Objekts erstellen müssen. Die gesamte Idee der Schnittstelle besteht darin, OOP-Konzepte mit der Einführung der statischen Methode einzuführen, die Sie vom Konzept ablenken.

VIckyb
quelle