2010-09-09 10 views
7

Esempio 1:Perché questi due esempi di codice producono output diversi?

class Animal { 
    public static void saySomething() { System.out.print(" Gurrr!"); 
    } 
} 
class Cow extends Animal { 
    public static void saySomething() { 
    System.out.print(" Moo!"); 
    } 
    public static void main(String [] args) { 
     Animal [] animals = {new Animal(), new Cow()}; 
     for(Animal a : animals) { 
      a.saySomething(); 
     } 
     new Cow().saySomething(); 
    } 
} 

uscita è:

Gurrr! Gurrr! Moo! 

Esempio 2:

class Animal { 
    public void saySomething() { System.out.print(" Gurrr!"); 
    } 
} 
class Cow extends Animal { 
    public void saySomething() { 
    System.out.print(" Moo!"); 
    } 
    public static void main(String [] args) { 
     Animal [] animals = {new Animal(), new Cow()}; 
     for(Animal a : animals) { 
      a.saySomething(); 
     } 
     new Cow().saySomething(); 
    } 
} 

uscita:

Gurrr! Moo! Moo! 

io proprio non capisco perché fare saySomething non-stat ic causa la seconda chiamata a sayqualcosa che richiama la versione Cow invece della versione Animal. La mia comprensione era che il Gurrr! Moo! Moo! sarebbe stato l'output in entrambi i casi.

+0

"La specifica del linguaggio Java dice così" è davvero tutto quello che c'è da fare. Perché sei autorizzato a chiamare un metodo statico da un riferimento di istanza come quello in primo luogo è la stranezza reale. Ma c'è già almeno un enorme thread wiki della comunità su questo :) – Affe

risposta

1

I metodi statici sono legati alla loro classe in fase di compilazione e non possono essere utilizzati in modo polimorfico. Quando dichiari un metodo "statico" su Animal, è legato per sempre alla classe Animal e non può essere sovrascritto. I metodi statici sono legati all'oggetto Class, non a un'istanza della classe.

I metodi regolari sono associati in fase di esecuzione e pertanto la JVM può visualizzare la chiamata su "say Something" e tentare di determinare se si sta passando attorno ad una sottoclasse di Animal e, in caso affermativo, ha sostituito il metodo saySomething(). I metodi regolari sono legati a un'istanza di un oggetto, non alla classe stessa.

Anche per questo motivo non si poteva mai fare questo:

class Animal 
{ 
    public abstract static void saySomething(); 
} 

Dal significa "statiche", "legate al momento della compilazione", non ha mai senso per qualcosa di cui essere statico e astratto.

7

Quando si chiama saySomething() su un animale, il tipo effettivo dell'animale non conta perché saySomething() è statico.

Animal cow = new Cow(); 
cow.saySomething(); 

è uguale

Animal.saySomething(); 

Un esempio JLS:

Quando viene calcolato un riferimento di destinazione e poi scartata poiché la modalità invocazione è statico, il riferimento è non esaminato per vedere se è nullo:

class Test { 
    static void mountain() { 
     System.out.println("Monadnock"); 
    } 
    static Test favorite(){ 
     System.out.print("Mount "); 
     return null; 
    } 
    public static void main(String[] args) { 
     favorite().mountain(); 
    } 

}

che stampa:
Monte Monadnock
Qui preferita torna nulla, eppure nessuno NullPointerException è gettato.


Risorse:

Sullo stesso argomento:

+1

Non ho mai capito perché Java consente l'invocazione di un metodo statico attraverso un riferimento a un oggetto. Non è necessario e porta a una confusione come questa. – erickson

+0

concordato. C++ ti permette di farlo anche tu. La mia ipotesi sarebbe che semplifica le cose per lo scrittore di compilatori per consentire questo tipo di accesso. –

+0

Beh, ho cercato di difenderlo qui: http://stackoverflow.com/questions/3610309/java-static-confusion/ –

3

Non è possibile di override metodi statici con la stessa firma in sottoclassi, basta nasconderli.

Per metodi di classe, il sistema runtime invoca il metodo definito nel tipo fase di compilazione del riferimento su cui viene chiamato il metodo. Ad esempio, il sistema runtime richiama il metodo definito nel tipo di runtime del riferimento su cui viene chiamato il metodo.

http://life.csu.edu.au/java-tut/java/javaOO/override.html

3

Alcune delle note di priorità assoluta "trappole"

  • metodi statici non possono essere invocati
  • metodi privati ​​non possono essere ridefinite

Questo spiega l'output.

1

I metodi statici sono legati alla "Classe", non all'istanza dell'oggetto. Poiché ci si riferisce a un "Animale" e si chiama il metodo statico say Something(). Farà sempre la chiamata a "Animal" a meno che non ti riferisca a una mucca.

Problemi correlati