2010-05-14 19 views
10

Ho un metodo statico definito in una classe base, voglio sovrascrivere questo metodo nella sua classe figlio, è possibile?È possibile sovrascrivere un metodo statico nella classe derivata?

Ho provato questo ma non ha funzionato come mi aspettavo. Quando ho creato un'istanza di classe B e invocato il suo metodo callMe(), viene invocato il metodo static foo() nella classe A.

public abstract class A { 
    public static void foo() { 
    System.out.println("I am base class"); 
    } 

    public void callMe() { 
    foo(); 
    } 
} 

Public class B { 
    public static void foo() { 
     System.out.println("I am child class"); 
    } 
} 
+2

Non si dovrebbe essere in primo luogo chiamando i metodi statici di un oggetto, dovresti chiamarlo dalla classe. –

risposta

16

Le chiamate al metodo statico vengono risolte in fase di compilazione (nessuna spedizione dinamica).

class main { 
    public static void main(String args[]) { 
      A a = new B(); 
      B b = new B(); 
      a.foo(); 
      b.foo(); 
      a.callMe(); 
      b.callMe(); 
    } 
} 
abstract class A { 
    public static void foo() { 
     System.out.println("I am superclass"); 
    } 

    public void callMe() { 
     foo(); //no late binding here; always calls A.foo() 
    } 
} 

class B extends A { 
    public static void foo() { 
     System.out.println("I am subclass"); 
    } 
} 

I am superclass 
I am subclass 
I am superclass 
I am superclass 
+0

Ho cambiato idea e ho scritto "no dynamic dispatch", poiché questo è il concetto generale coinvolto. – Artefacto

+0

Uh, non si usa affatto callMe() ... – RCIX

+1

I termini corretti sono "superclasse" e "sottoclasse", non "classe base" e "classe figlio". – Jesper

0

No. Non è possibile.

Alcune domande simili (non uguali) here e here.

4

In Java, ricerche metodo statico vengono determinati in fase di compilazione e non può adattarsi a sottoclassi caricate dopo la compilazione.

1

Solo per aggiungere un perché a questo. Normalmente quando si chiama un metodo viene utilizzato l'oggetto a cui appartiene il metodo per trovare l'implementazione appropriata. Si ottiene la possibilità di sovrascrivere un metodo facendo in modo che un oggetto fornisca il proprio metodo invece di utilizzare quello fornito dal genitore.

Nel caso di metodi statici non vi è alcun oggetto da utilizzare per indicare quale implementazione utilizzare. Ciò significa che il compilatore può utilizzare solo il tipo dichiarato per scegliere l'implementazione del metodo da chiamare.

0

I metodi statici vengono risolti in fase di compilazione. Pertanto, se si desidera chiamare il metodo della classe padre, è necessario chiamare esplicitamente con className o istanza come di seguito.

A.foo(); 

o

A a = new A(); 
a.foo(); 
24

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

0

In poche parole, il metodo statico che sovrascrive non è il polimorfismo, è "metodo nascosto". Quando si esegue l'override di un metodo statico non si avrà accesso al metodo della classe base poiché verrà nascosto dalla classe derivata. L'utilizzo di super() genererà un errore di compilazione.

Problemi correlati