Comportamento del metodo statico finale


123

Ho giocato con modificatori con metodo statico e mi sono imbattuto in un comportamento strano.

Come sappiamo, i metodi statici non possono essere sovrascritti, poiché sono associati alla classe piuttosto che all'istanza.

Quindi, se ho lo snippet di seguito, si compila bene

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

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

Ma se includo il modificatore finale al metodo statico nella classe A, la compilazione fallisce ts () in B non può sovrascrivere ts () in A; il metodo sostituito è statico finale .

Perché succede quando il metodo statico non può essere assolutamente sovrascritto?


2
sembra strano, +1 per la domanda, ma fino ad ora nessuna delle risposte è soddisfacente.
Rakesh Juyal,

1
Non è sovrascritto. È ancora lì ad A.ts ().
Alex Feinman

Risposte:


166

I metodi statici non possono essere sovrascritti ma possono essere nascosti. Il ts()metodo di B non sovrascrive (non soggetto a polimorfismo) il metodo di ts()A ma lo nasconde. Se chiami ts()in B (NOT A.ts()o B.ts()... solo ts()), verrà chiamata quella di B e non A. Poiché questa non è soggetta a polimorfismo, la chiamata ts()in A non sarà mai reindirizzata a quella in B.

La parola chiave finaldisabiliterà il metodo dall'essere nascosto. Quindi non possono essere nascosti e un tentativo di farlo risulterà in un errore del compilatore.

Spero che questo ti aiuti.


30
Per finire forse la tua risposta, che credo sia giusta, il problema qui è fondamentalmente un cattivo messaggio di errore del compilatore: dovrebbe dire che B non può nascondere ts () in A. Dichiarare un metodo statico finale significa dichiarare che non può essere nascosto.
Sean Owen,

2
@ Sean Owen: lo penso anch'io. Il termine "nascondi" viene utilizzato anche nelle specifiche Java, quindi perché non utilizzarlo nel messaggio del compilatore.
NawaMan,

2
Perché anche questa è una caratteristica? In quale contesto sarebbe utile?
user253751

public class Test {final static public void main (String ... srik) {System.out.println ("In main method"); ts (); } public static void ts () {Child c = new Child (); c.ts (); System.out.println ("Test ts"); }} public class Child estende Test {public static void ts () {System.out.println ("Child ts"); }} Ciao, puoi spiegarmi cosa succede in questo scenario
srikanth r

@SeanOwen Non penso nemmeno che questo sia corretto, il compilatore dovrebbe dire che poiché A#tsviene ereditato e un tale metodo esiste già B, semplicemente avere due metodi con la stessa firma e un modificatore diverso ( final) non funzionerebbe come overload .. Vorrei poter pensare a un semplice messaggio per questo, però
Eugene

13

i metodi statici non possono essere sovrascritti

Questo non è esattamente vero. Il codice di esempio significa davvero che il metodo ts in B nasconde il metodo ts in A. Quindi non è esattamente sovrascrivente. Su Javaranch c'è una bella spiegazione.


4
È vero solo non preciso. i metodi statici non possono essere sovrascritti ma possono essere nascosti se li stai chiamando su un riferimento a un'istanza anziché sul nome della classe.
John Mercier,

1
Purtroppo il tuo link non funziona più. È possibile risolvere questo problema?
Mathias Bader

Il collegamento a javaranch non funziona, ma le parole chiave su Google hanno trovato questo collegamento su Code Ranch
Sundeep

Ho modificato il post sostituendo il link morto con il link pubblicato da Sundeep.
MC Emperor

10

I metodi statici appartengono alla classe, non all'istanza.

A.ts()e B.ts()saranno sempre metodi separati.

Il vero problema è che Java ti consente di chiamare metodi statici su un oggetto istanza. I metodi statici con la stessa firma della classe genitore vengono nascosti quando vengono chiamati da un'istanza della sottoclasse. Tuttavia, non è possibile sovrascrivere / nascondere i metodi finali .

Penseresti che il messaggio di errore utilizzi la parola nascosta invece di sovrascritta ...


6

Potresti trovarti nella posizione di pensare di rendere definitivo un metodo statico, considerando quanto segue:

Avere le seguenti classi:

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

Ora il modo "corretto" per chiamare questi metodi sarebbe

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

che risulterebbe ABma potresti anche chiamare i metodi sulle istanze:

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

che risulterebbe ABanche.

Ora considera quanto segue:

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

che verrebbe stampato A. Questo potrebbe sorprenderti visto che stai effettivamente avendo un oggetto di classe B. Ma poiché lo chiami da un riferimento di tipo A, chiamerà A.ts(). Puoi stampare Bcon il seguente codice:

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

In entrambi i casi l'oggetto che hai è effettivamente di classe B. Ma a seconda del puntatore che punta all'oggetto, chiamerai il metodo da Ao da B.

Supponiamo ora che tu sia lo sviluppatore della classe Ae desideri consentire la sottoclasse. Ma vuoi davvero il metodo ts(), ogni volta che viene chiamato, anche da una sottoclasse, che fa quello che vuoi che faccia e non sia nascosto da una versione della sottoclasse. Quindi potresti farlo finale impedire che venga nascosto nella sottoclasse. E puoi essere certo che il seguente codice chiamerà il metodo dalla tua classe A:

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

Ok, ammettetamente che è in qualche modo costruito, ma potrebbe avere senso per alcuni casi.

Non dovresti chiamare metodi statici sulle istanze ma direttamente sulle classi, quindi non avrai quel problema. Anche IntelliJ IDEA, ad esempio, ti mostrerà un avviso, se chiami un metodo statico su un'istanza e anche se rendi finale un metodo statico.


0

Il metodo ts () in B non sovrascrive il metodo ts () in A, è semplicemente un altro metodo. La classe B non vede il metodo ts () in A poiché è statico, quindi può dichiarare il proprio metodo chiamato ts ().

Tuttavia, se il metodo è definitivo, il compilatore rileverà che esiste un metodo ts () in A che non dovrebbe essere sovrascritto in B.


Non credo che questo spieghi perché "finale" improvvisamente significa che questi metodi non possono coesistere. Come dici tu, senza "finale", non c'è problema. Dici che non ha la precedenza, ma poi dici che il problema è che B non può sovrascrivere il metodo di A.
Sean Owen,

Certo, premetto che B non vede il metodo ts () in A (è 'nascosto'), ma il modificatore finale non 'nasconde' i metodi dalle classi che ne estendono un altro. Ma eh, ok.
amischiefr

0

Penso che l'errore di compilazione sia stato abbastanza fuorviante qui. Non avrebbe dovuto dire "il metodo sovrascritto è finale statico", ma avrebbe dovuto invece dire "il metodo sostituito è finale". Il modificatore statico è irrilevante qui.


1
Quindi consideri il metodo statico in B sovrascrivendo quello in A?
Koray Tugay

@KorayTugay Mi chiedo solo se il compilatore prima guarda il metodo potenzialmente sovrascrivibile (ignora statico per un momento), vede il finale a fallisce. Solo un'ipotesi folle però
Eugene

Balus Penso che questa sia l'unica risposta di bassa qualità che hai in StackOverflow. Considerando tutte le tue risposte eccezionali, questa non appartiene a loro. @BalusC
Koray Tugay

@KorayTugay: a quel tempo non avevo abbastanza reputazione per commentare :) Se rispondi, cancellerò la risposta, nessun problema.
BalusC

0

Un metodo statico non può essere sovrascritto in Java, a differenza dei metodi non statici. Ma vengono ereditati come membri di dati statici e non statici. Ecco perché un metodo non statico con lo stesso nome non può essere creato nella classe genitore

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
    }
}

La finalparola chiave garantisce che il corpo del metodo specifico venga eseguito ogni volta che viene chiamata al metodo. Ora se un metodo statico viene creato nella classe figlia con lo stesso nome e viene effettuata una chiamata al metodo, viene eseguito il metodo nella sottoclasse, il che non dovrebbe essere il caso se final è preceduto dal nome del metodo statico nella classe genitore . Quindi la parola chiave finale limita la creazione del metodo con lo stesso nome nella classe figlia.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.