2009-11-16 24 views
94

Ho giocato con i modificatori con il metodo statico e mi sono imbattuto in un comportamento strano.Comportamento del metodo statico finale

Come sappiamo, i metodi statici non possono essere sovrascritti, in quanto associati alla classe anziché all'istanza.

Quindi, se ho il frammento di codice 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 in classe A, quindi la compilazione fallisce ts() in B non può ignorare ts() in un; il metodo sovrascritto è statico finale.

Perché ciò accade quando il metodo statico non può essere sovrascritto?

+0

sembra strano, +1 per la domanda, ma fino ad ora nessuna delle risposte sono soddisfacenti. –

+1

Non è sovrascritto. È ancora lì a A.ts(). –

risposta

131

I metodi statici non possono essere sovrascritti ma possono essere nascosti. Il metodo ts() di B non è prioritario (non soggetto a polimorfismo) il ts() di A, ma lo nasconderà. Se chiami ts() in B (NON A.ts() o B.ts() ... solo ts()), quello di B sarà chiamato e non A. Poiché questo non è soggetto al polimorfismo, la chiamata ts() in A non verrà mai reindirizzata a quella in B.

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

Spero che questo aiuti.

+25

Per terminare forse la risposta, che si trova proprio credo, il problema qui è fondamentalmente un messaggio di errore del compilatore male: dovrebbe dice B non può * nascondere * ts() in A. dichiarare un metodo statico finale sta dichiarando che non può essere nascosta. –

+2

@Sean Owen: lo penso anch'io. Il termine "nascondi" è anche usato nelle specifiche Java, quindi perché non usarlo nel messaggio del compilatore. – NawaMan

+2

Perché questa è anche una funzione? In quale contesto sarebbe utile? – immibis

11

metodi statici non possono essere sovrascritte

Questo non è esattamente vero. Il codice di esempio in realtà significa che il metodo ts in B nasconde il metodo ts in A. Quindi non è esattamente override. Oltre a Javaranch c'è una bella spiegazione.

+3

È vero, non è preciso. i metodi statici non possono essere sovrascritti ma possono essere nascosti se li si chiama su un riferimento di istanza piuttosto che sul nome della classe. –

+0

Sfortunatamente il tuo link non funziona più. È possibile risolvere questo problema? –

0

Il metodo ts() in B non sta sovrascrivendo 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 è definitiva, quindi il compilatore prelevamento che esiste un metodo ts() in A che non dovrebbe essere ignorato in B.

+0

Non penso che questo spieghi perché 'finale' significa improvvisamente che questi metodi non possono coesistere. Come dici tu, senza 'finale', non c'è problema. Dici che non è esagerato, ma poi dì che il problema è che B non può sovrascrivere il metodo di A. –

+0

Certo che lo fa, 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

9

metodi statici appartengono alla classe, non l'istanza .

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

Il vero problema è che Java consente di chiamare metodi statici su un oggetto istanza. I metodi statici con la stessa firma della classe genitore sono hidden quando vengono chiamati da un'istanza della sottoclasse. Tuttavia, non è possibile ignorare/nascondere final methods.

si potrebbe pensare che il messaggio di errore potrebbe usare la parola nascosta, invece di sovrascritto ...

1

penso che l'errore di compilazione è del tutto fuorviante qui. Non avrebbe dovuto dire che "il metodo sovrascritto è statico finale", ma dovrebbe invece dire che "il metodo sovrascritto è definitivo". Il modificatore statico è irrilevante qui.

+0

Quindi consideri il metodo statico in B sovrascrivendo quello in A? –

4

Potreste trovarvi nella posizione di pensare di fare un ultimo metodo statico, considerando quanto segue:

aventi 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' a chiamare questi metodi sarebbe

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

che si tradurrebbe in AB ma si potrebbe anche chiamare i metodi su casi:

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

che risulterebbe in AB pure.

Consideriamo ora il seguente:

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

che stampare A. Questo potrebbe sorprenderti dato che hai effettivamente un oggetto della classe B. Ma dal momento che lo chiami da un riferimento di tipo A, chiamerà A.ts(). Si potrebbe stampare B con il seguente codice:

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

In entrambi i casi l'oggetto che hai è in realtà dalla classe B. Ma a seconda del puntatore che punta all'oggetto, chiamerai il metodo da A o da B.

Ora supponiamo che tu sia lo sviluppatore della classe A e desideri consentire la sottoclassificazione. Ma vuoi davvero il metodo ts(), ogni volta che viene chiamato, anche da una sottoclasse, cioè fa ciò che vuoi che faccia e non sia nascosto da una versione di sottoclasse. Quindi potresti renderlo final e impedire che venga nascosto nella sottoclasse. E si può essere sicuri che il seguente codice chiamerà il metodo dalla classe A:

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

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

Non dovresti chiamare metodi statici su istanze ma direttamente sulle classi - quindi non avrai questo problema. Ad esempio, IntelliJ IDEA ti mostrerà un avviso, se chiami un metodo statico su un'istanza e anche se definisci un metodo statico definitivo.

Problemi correlati