2010-05-08 11 views
16

Kann jemand im Detail den Grund erklären, warum die überladene Methode print(Parent parent) aufgerufen wird, wenn mitInstanz in meinem Test Stück Code arbeiten?Java-Methode Überladung + Doppelversand

Irgendwelche Besonderheiten von virtuellen Methoden oder Methoden Überladung/Auflösung in Java beteiligt? Eine direkte Referenz zu Java Lang Spec? Welcher Begriff beschreibt dieses Verhalten? Vielen Dank.

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); 
    } 
} 

Antwort

23

Die JLS Zustände in §8.4.9 Overloading:

  1. Wenn eine Methode (§15.12) aufgerufen wird, die Anzahl der aktuellen Argumente (und alle expliziten Typargumente) und die Kompilierzeit-Typen der Argumente sind wird zur Kompilierzeit verwendet, um die Signatur der Methode zu ermitteln, die aufgerufen wird (§15.12.2).
  2. Wenn es sich bei der Methode, die aufgerufen werden soll, um eine Instanzmethode handelt, wird die tatsächliche Methode, die aufgerufen werden soll, zur Laufzeit mithilfe der Methode dynamic method lookup (§15.12.4) ermittelt.

So in Ihrem Fall:

  1. Verfahren Argument (this) ist der Kompilierung-Typ Parent, und so das Verfahren print(Parent) aufgerufen wird.
  2. Wenn die Klasse Worker Unterklasse wurde und die Unterklasse diese Methode überschreiben würde und die worker Instanz dieser Unterklasse wäre, würde die überschriebene Methode aufgerufen.

Double-Versand existiert nicht in Java. Sie müssen es simulieren, z.B. mit der Visitor Pattern. In diesem Muster implementiert im Grunde jede Unterklasse eine accept-Methode und ruft den Besucher mit this als Argument auf, und this hat als Kompilierzeit diese Unterklasse, so dass die gewünschte Methodenüberladung verwendet wird.

+0

Christian, danke für die ausführliche Antwort! So behandeln wir hier mit Laufzeit VS compiletime Typen Sache. Ich werde viel über dieses Thema nachdenken. (Doppel-Versand ist hier erwähnt, weil ich über diese Frage rannte über die sehr Besucher Muster :)). max – Max

5

Der Grund dafür ist, dass doJob in Parent implementiert ist und nicht in Child überlastet. Es übergibt this an die print methos des Mitarbeiters, weil this vom Typ Parent die Methode Worker::print(Parent) genannt wird.

Um Worker::print(Parent) Sie needto Überlastung genannt zu haben 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); 
    } 
} 

In dem obigen Code this.getClass() in Child-Child.class entspricht.

+0

rsp, danke für das Zeigen, aber ich weiß, dass überschreiben doJob in Child Prog Arbeit macht. Die Sache ist, dass ich nicht verstehe warum :). Werfen wir einen Blick auf den ursprünglichen Code. Wenn wir Child-Objekt an Parent.doJob übergeben, zeigt die Java-Reflektion in Parent.doJob, dass wir uns mit dem Typ Child beschäftigen, also warum schlägt die Auflösung der überladenen Methode fehl? – Max

+1

@Max, innerhalb einer Methode ist der Typ von 'this' immer der Typ der Klasse, in der sich die Methode befindet.Der Compiler kann nicht wissen, dass die Klasse in Zukunft zu dem Ererbten geht, er muss das Wissen verwenden, das er zu diesem Zeitpunkt hat. 'this.getClass()' ist Laufzeitinformationen, keine Kompilierzeit. – rsp

+0

rsp, vielen Dank. habe es schon. – Max