Can I override a static method?
Molte persone hanno sentito che non si può ignorare un metodo statico. Questo è vero - non puoi. Tuttavia è possibile scrivere codice come questo:
class Foo {
public static void method() {
System.out.println("in Foo");
}
}
class Bar extends Foo {
public static void method() {
System.out.println("in Bar");
}
}
Questo compila e funziona bene. Non è un esempio di un metodo statico che sovrascrive un altro metodo statico? La risposta è no - è un esempio di un metodo statico che nasconde un altro metodo statico. Se provi a sovrascrivere un metodo statico, il compilatore non ti ferma effettivamente, semplicemente non fa quello che pensi che faccia.
Quindi qual è la differenza?
In breve, quando si esegue l'override di un metodo, si ottengono comunque i vantaggi del polimorfismo di runtime e, quando si nasconde, non lo si fa. Che cosa vuol dire?Date un'occhiata a questo codice:
class Foo {
public static void classMethod() {
System.out.println("classMethod() in Foo");
}
public void instanceMethod() {
System.out.println("instanceMethod() in Foo");
}
}
class Bar extends Foo {
public static void classMethod() {
System.out.println("classMethod() in Bar");
}
public void instanceMethod() {
System.out.println("instanceMethod() in Bar");
}
}
class Test {
public static void main(String[] args) {
Foo f = new Bar();
f.instanceMethod();
f.classMethod();
}
}
Se si esegue questo, l'uscita è
instanceMethod() nella barra
classmethod() in Foo
Perché otteniamo instanceMethod da Bar, ma classMethod() di Foo? Non stiamo usando la stessa istanza f per accedere a entrambi? Sì, lo siamo - ma dal momento che uno sta scavalcando e l'altro si nasconde, vediamo un comportamento diverso.
Poiché instanceMethod() è (rullo di tamburi per favore ...) un metodo di istanza, in cui la barra esegue l'override del metodo da Foo, in fase di esecuzione la JVM utilizza la classe effettiva dell'istanza f per determinare quale metodo eseguire. Sebbene f sia stato dichiarato come Foo, l'istanza effettiva che abbiamo creato era una nuova barra(). Quindi in fase di esecuzione, la JVM rileva che f è un'istanza di Bar, e quindi chiama instanceMethod() in Bar piuttosto che in Foo. Ecco come Java normalmente funziona per metodi di istanza.
Con classMethod(). poiché (ahem) è un metodo di classe, il compilatore e JVM non si aspettano di aver bisogno di un'istanza reale per invocare il metodo. E anche se ne fornite uno (cosa che abbiamo fatto: l'istanza a cui fa riferimento f), la JVM non la guarderà mai. Il compilatore esaminerà solo il tipo dichiarato del riferimento e utilizzerà quel tipo dichiarato per determinare, in fase di compilazione, quale metodo chiamare. Poiché f è dichiarato come tipo Foo, il compilatore guarda f.classMethod() e decide che significa Foo.classMethod. Non importa che l'istanza a cui fa riferimento f sia in realtà una barra: per i metodi statici, il compilatore utilizza solo il tipo dichiarato del riferimento. Questo è ciò che intendiamo quando diciamo che un metodo statico non ha il polimorfismo di runtime.
Poiché i metodi di istanza e i metodi di classe presentano questa importante differenza di comportamento, vengono utilizzati termini diversi - "sovrascrittura" per i metodi di istanza e "occultamento" per i metodi di classe - per distinguere tra i due casi. E quando diciamo che non puoi scavalcare un metodo statico, significa che anche se scrivi un codice che sembra sovrascrivere un metodo statico (come il primo Foo e la barra in cima a questa pagina) - non lo farà comportarsi come un metodo sovrascritto. per ulteriori rimandi this
Non si dovrebbe essere in primo luogo chiamando i metodi statici di un oggetto, dovresti chiamarlo dalla classe. –