Verhalten der endgültigen statischen Methode

123

Ich habe mit Modifikatoren mit statischer Methode herumgespielt und bin auf ein seltsames Verhalten gestoßen.

Wie wir wissen, können statische Methoden nicht überschrieben werden, da sie eher der Klasse als der Instanz zugeordnet sind.

Wenn ich also das folgende Snippet habe, wird es gut kompiliert

//Snippet 1 - Compiles fine
public class A {
    static void ts() {
    }
}

class B extends A {
    static void ts() {
    }
}

Wenn ich jedoch den letzten Modifikator für die statische Methode in Klasse A einbinde, schlägt die Kompilierung fehl. Ts () in B kann ts () in A nicht überschreiben. überschriebene Methode ist statisch final .

Warum passiert dies, wenn die statische Methode überhaupt nicht überschrieben werden kann?

Harish
quelle
2
es scheint seltsam, +1 für die Frage, aber bis jetzt ist keine der Antworten zufriedenstellend.
Rakesh Juyal
1
Es wird nicht überschrieben. Es ist immer noch da bei A.ts ().
Alex Feinman

Antworten:

166

Statische Methoden können nicht überschrieben, aber ausgeblendet werden. Die ts()Methode von B überschreibt nicht die ts()von A (unterliegt keinem Polymorphismus), sondern verbirgt sie. Wenn Sie ts()B anrufen (NICHT A.ts()oder B.ts()... nur ts()), wird der von B und nicht A aufgerufen. Da dies keinem Polymorphismus unterworfen ist, wird der Anruf ts()in A niemals zu dem in B umgeleitet.

Das Schlüsselwort verhindert final, dass die Methode ausgeblendet wird. Sie können also nicht ausgeblendet werden, und ein Versuch dazu führt zu einem Compilerfehler.

Hoffe das hilft.

NawaMan
quelle
30
Um Ihre Antwort vielleicht zu beenden, was meines Erachtens richtig ist, ist das Problem hier im Grunde eine schlechte Compiler-Fehlermeldung: Es sollte lauten, dass B ts () in A nicht verbergen kann . Wenn Sie eine statische Methode final deklarieren, bedeutet dies, dass sie nicht ausgeblendet werden kann.
Sean Owen
2
@ Sean Owen: Das denke ich auch. Der Begriff "verstecken" wird sogar in der Java-Spezifikation verwendet. Warum also nicht in der Compiler-Nachricht verwenden?
NawaMan
2
Warum ist das überhaupt eine Funktion? In welchem ​​Kontext wäre es nützlich?
user253751
public class Test {endgültige statische öffentliche Leere main (String ... srik) {System.out.println ("In main method"); ts (); } public static void ts () {Kind c = neues Kind (); c.ts (); System.out.println ("Test ts"); }} public class Child erweitert Test {public static void ts () {System.out.println ("Child ts"); }} Hallo Can u plz mir erklären , was in diesem Szenario geschieht
srikanth r
@ SeanOwen Ich denke auch nicht, dass dies korrekt ist. Der Compiler sollte sagen, dass, da A#tser vererbt wird und eine solche Methode bereits vorhanden ist B, einfach zwei Methoden mit derselben Signatur und einem anderen Modifikator ( final) nicht als Überladung funktionieren würden. Ich wünschte, ich könnte mir eine einfache Nachricht dafür vorstellen
Eugene
13

statische Methoden können nicht überschrieben werden

Das ist nicht genau richtig. Der Beispielcode bedeutet wirklich, dass die Methode ts in B die Methode ts in A verbirgt. Sie wird also nicht genau überschrieben. Drüben auf Javaranch gibt es eine schöne Erklärung.

Vincent Ramdhanie
quelle
4
Es ist wahr, einfach nicht genau. statische Methoden können nicht überschrieben, aber ausgeblendet werden, wenn Sie sie für eine Instanzreferenz und nicht für den Klassennamen aufrufen.
John Mercier
1
Leider funktioniert Ihr Link nicht mehr. Ist es möglich, dies zu beheben?
Mathias Bader
Der Javaranch-Link funktioniert nicht, aber das Googeln der Schlüsselwörter hat diesen Link auf der Code-Ranch
Sundeep
Ich habe den Beitrag bearbeitet, indem ich den toten Link durch den von Sundeep geposteten Link ersetzt habe.
MC Emperor
10

Statische Methoden gehören zur Klasse, nicht zur Instanz.

A.ts()und B.ts()werden immer getrennte Methoden sein.

Das eigentliche Problem ist, dass Sie mit Java statische Methoden für ein Instanzobjekt aufrufen können. Statische Methoden mit derselben Signatur aus der übergeordneten Klasse werden ausgeblendet, wenn sie von einer Instanz der Unterklasse aufgerufen werden. Sie können die endgültigen Methoden jedoch nicht überschreiben / ausblenden .

Sie würden denken, die Fehlermeldung würde das Wort versteckt anstelle von überschrieben verwenden ...

Powerlord
quelle
6

Möglicherweise sind Sie in der Lage, über eine endgültige statische Methode nachzudenken, wenn Sie Folgendes berücksichtigen:

Folgende Klassen haben:

class A {
    static void ts() {
        System.out.print("A");
    }
}
class B extends A {
    static void ts() {
        System.out.print("B");
    }
}

Nun wäre die "richtige" Art, diese Methoden aufzurufen

A.ts();
B.ts();

Dies würde dazu führen, ABaber Sie könnten die Methoden auch für Instanzen aufrufen:

A a = new A();
a.ts();
B b = new B();
b.ts();

was auch dazu führen würde AB.

Betrachten Sie nun Folgendes:

A a = new B();
a.ts();

das würde drucken A. Das könnte Sie überraschen, da Sie tatsächlich ein Klassenobjekt haben B. Da Sie es jedoch von einer Referenz des Typs aus aufrufen A, wird es aufgerufen A.ts(). Sie können Bmit folgendem Code drucken :

A a = new B();
((B)a).ts();

In beiden Fällen stammt das Objekt, das Sie haben, tatsächlich aus der Klasse B. Abhängig vom Zeiger, der auf das Objekt zeigt, rufen Sie die Methode von Aoder von auf B.

Angenommen, Sie sind der Entwickler der Klasse Aund möchten die Unterklassifizierung zulassen. Aber Sie möchten wirklich, dass die Methode ts(), wann immer sie aufgerufen wird, auch von einer Unterklasse, genau das tut, was Sie möchten, und nicht von einer Unterklassenversion ausgeblendet wird. Dann könnten Sie es schaffen finalund verhindern, dass es in der Unterklasse versteckt wird. Und Sie können sicher sein, dass der folgende Code die Methode aus Ihrer Klasse aufruft A:

B b = new B();
b.ts();

Ok, zugegeben, das ist irgendwie konstruiert, aber es könnte in einigen Fällen Sinn machen.

Sie sollten keine statischen Methoden für Instanzen aufrufen, sondern direkt für die Klassen - dann haben Sie dieses Problem nicht. Auch IntelliJ IDEA zeigt Ihnen beispielsweise eine Warnung an, wenn Sie eine statische Methode für eine Instanz aufrufen und wenn Sie eine statische Methode endgültig machen.

Mathias Bader
quelle
0

Die ts () -Methode in B überschreibt nicht die ts () -Methode in A, sondern ist einfach eine andere Methode. Die B-Klasse sieht die ts () -Methode in A nicht, da sie statisch ist. Daher kann sie ihre eigene Methode mit dem Namen ts () deklarieren.

Wenn die Methode jedoch endgültig ist, stellt der Compiler fest, dass es in A eine ts () -Methode gibt, die in B nicht überschrieben werden sollte.

amischiefr
quelle
Ich glaube nicht, dass dies erklärt, warum 'final' plötzlich bedeutet, dass diese Methoden nicht koexistieren können. Wie Sie sagen, ohne "final" gibt es kein Problem. Sie sagen, es wird nicht überschrieben, aber dann sagen Sie, das Problem ist, dass B die Methode von A nicht überschreiben kann.
Sean Owen
Sicher, ich sage, dass B die Methode ts () in A nicht sieht (sie ist 'versteckt'), aber der letzte Modifikator 'versteckt' Methoden nicht vor Klassen, die eine andere erweitern. Aber eh, ok.
Amischiefr
0

Ich denke, der Kompilierungsfehler war hier ziemlich irreführend. Es sollte nicht "Überschriebene Methode ist statisch endgültig" stehen, sondern "Überschriebene Methode ist endgültig". Der statische Modifikator spielt hier keine Rolle.

BalusC
quelle
1
Sie betrachten also die statische Methode in B als die in A überschreibend?
Koray Tugay
@KorayTugay Ich frage mich nur, ob der Compiler zuerst die potenziell überschreibbare Methode betrachtet (ignoriert statische für einen Moment) und sieht, dass final bei fehlschlägt. Nur eine wilde Vermutung
Eugene
Balus Ich denke, dies ist die einzige Antwort von geringer Qualität, die Sie in StackOverflow haben. In Anbetracht all Ihrer außergewöhnlichen Antworten gehört diese nicht zu ihnen. @ BalusC
Koray Tugay
@KorayTugay: Zu dieser Zeit hatte ich nicht genug Ruf, um einen Kommentar abzugeben :) Wenn Sie zurückpingen, werde ich die Antwort löschen, kein Problem.
BalusC
0

Eine statische Methode kann in Java im Gegensatz zu nicht statischen Methoden nicht überschrieben werden. Sie werden jedoch wie statische und nicht statische Datenelemente vererbt. Aus diesem Grund kann in der übergeordneten Klasse keine nicht statische Methode mit demselben Namen erstellt werden

class Writer { 
    public static void doo(){
        System.out.println("sth");
    } 
}
class Author extends Writer{ 
    public void doo(){
        System.out.println("ok"); // error overridden method is static
    }
}

Das finalSchlüsselwort stellt sicher, dass der spezifische Methodenkörper bei jedem Aufruf der Methode ausgeführt wird. Wenn nun in der untergeordneten Klasse eine statische Methode mit demselben Namen erstellt und die Methode aufgerufen wird, wird die Methode in der Unterklasse ausgeführt. Dies sollte nicht der Fall sein, wenn final vor dem statischen Methodennamen in der übergeordneten Klasse steht . Daher beschränkt das letzte Schlüsselwort die Erstellung einer Methode mit demselben Namen in der untergeordneten Klasse.

Pratik Gupta
quelle