2010-05-08 15 views
16

Qualcuno può spiegare in dettaglio la ragione per cui il metodo sovraccarico print(Parent parent) viene richiamato quando si lavora con l'istanza Child nella mia parte di codice di prova?Sovraccarico del metodo Java + doppia spedizione

Qualunque particolarità dei metodi virtuali o dei metodi di sovraccarico/risoluzione in Java coinvolti qui? Qualsiasi riferimento diretto a Java Lang Spec? Quale termine descrive questo comportamento? Grazie mille.

public class InheritancePlay { 

    public static class Parent {   
     public void doJob(Worker worker) { 
      System.out.println("this is " + this.getClass().getName()); 

      worker.print(this); 
     } 
    } 

    public static class Child extends Parent { 
    } 

    public static class Worker { 
     public void print(Parent parent) { 
      System.out.println("Why this method resolution happens?"); 
     } 

     public void print(Child child) { 
      System.out.println("This is not called"); 
     } 
    } 

    public static void main(String[] args) { 
     Child child = new Child(); 
     Worker worker = new Worker(); 

     child.doJob(worker); 
    } 
} 

risposta

23

Gli stati GLS in §8.4.9 Overloading:

  1. Quando un metodo viene richiamato (§15.12), il numero di argomenti reali (ed eventuali argomenti di tipo esplicite) ei tipi di compilazione degli argomenti sono usato, in fase di compilazione, per determinare la firma del metodo che verrà invocato (§15.12.2).
  2. Se il metodo che deve essere richiamato è un metodo di istanza, il metodo effettivo da richiamare verrà determinato in fase di esecuzione, utilizzando la ricerca del metodo dinamico (§15.12.4).

Quindi nel tuo caso:

  1. L'argomento del metodo (this) è del tipo in fase di compilazione Parent, e così il metodo print(Parent) viene richiamato.
  2. Se la classe Worker è stata sottoclasse e la sottoclasse sostituirà tale metodo e l'istanza worker era di quella sottoclasse, il metodo sottoposto a override verrà invocato.

La doppia spedizione non esiste in Java. Devi simularlo, ad es. utilizzando lo Visitor Pattern. In questo modello, fondamentalmente, ciascuna sottoclasse implementa un metodo accept e chiama il visitatore con this come argomento e this ha come tipo di sottoclasse in fase di compilazione, quindi viene utilizzato l'overloading del metodo desiderato.

+0

Christian, grazie per esauriente risposta! Quindi ci occupiamo di runtime VS compiletime types. Scaverò molto in quell'argomento (La doppia spedizione è menzionata qui perché mi sono imbattuto in questa domanda interpretando il modello molto Visitatore :)). Max – Max

5

La ragione è che doJob è implementato in Parent e non sovraccaricato in Child. Passa this ai methos print del lavoratore, perché this è del tipo Parent verrà chiamato il metodo Worker::print(Parent).

Al fine di avere Worker::print(Parent) ti ha chiamato needto sovraccarico doJob in Child:

public static class Child extends Parent { 
    public void doJob(Worker worker) { 
     System.out.println("from Child: this is " + this.getClass().getName()); 

     worker.print(this); 
    } 
} 

Nel codice di cui sopra this.getClass() in Child è equivalente a Child.class.

+0

rsp, grazie per aver indicato questo, ma so che l'override di DoJob in Child rende il prog lavoro. Il fatto è che non capisco perché :). Diamo un'occhiata al codice iniziale. Passando l'oggetto figlio a Parent.doJob, la riflessione Java all'interno di Parent.doJob dimostra che ci occupiamo di questo di tipo Child, quindi perché la risoluzione del metodo sovraccarico non riesce? – Max

+1

@Max, all'interno di un metodo il tipo di "questo" è sempre il tipo di classe in cui si trova il metodo.Il compilatore non può sapere che la classe verrà ereditata da in futuro, deve usare la conoscenza che ha a quel punto. 'this.getClass()' è informazioni di runtime, non tempo di compilazione. – rsp

+0

rsp, grazie mille. ce l'ho già. – Max