2010-02-14 11 views
5

Ich habe eine Basisklasse namens Element. Einige andere Klassen (wie Label und Image) erweitern diese Klasse.Überladene Methoden Priorität

Ich habe jetzt eine Abfertigungs-Klasse die folgenden Methoden mit:

public class Dispatcher { 
    public static AbstractPropertyEditor<Label> createEditor(Label e) { 
    ... 
    } 

    public static AbstractPropertyEditor<Element> createEditor(Element e) { 
    ... 
    } 
} 

Wenn ich jetzt eine Instanz von Label haben (das Element erstreckt) und ich möchte es createEditor() passieren, ist, warum die meisten generische Methode (der zweite) angerufen? Wäre es nicht normal, dass die spezifische Methode (createEditor(Label e)) aufgerufen wird?

Ich brauche unbedingt die Methode mit dem Element-param, um „fangen“ all jenen Klassen, das Element a) implementieren, sondern ihr eigenes spezifisches Verfahren nicht in dieser Dispatching Klasse hat ..

Ich verwende Java 6, wie man das "repariert"?

Edit: Okay, ich muss zugeben, es geht überhaupt nicht um Generika. Aber da bin ich dem ersten Mal begegnet.

Danke und Grüße

+0

Sie haben die Instanz einer Variablen vom Typ 'Label' zugewiesen, nicht' Element'? –

+0

(und nicht von 'T extends Element' wo' T' zufällig 'Label' ist?) –

Antwort

6

Warum nicht Sie:

  • machen Element abstrakte Klasse, die eine Standard-Implementierung createEditor() bietet
  • make Label die createEditor() außer Kraft setzen.

So werden Sie die statischen Dienstprogramme nicht benötigen und Ihr Ziel erreichen.

Wenn Sie Element eine Schnittstelle zu sein, dann gilt:

  • definieren createEditor() als Methoden der Element
  • definieren eine EditorFactory Schnittstelle
  • bieten DefaultEditorFactory und ListEditorFactory
  • verwenden Sie die entsprechenden Fabriken in die Implementatoren von Element:

    public Editor createEditor() { 
        editorFactory.createEditor(this); 
    } 
    

wo der Beton EditorFactory entweder während der Initialisierung instanziiert wird oder über irgendeine Art von dependecy-Injektion.


Gemäß Ihrer konkreten Frage - es kommt darauf an, welchen Typ Sie dort zusammengestellt haben. Wenn Sie createEditor(obj) anrufen wird es abhängen, ob es Element obj = .. oder Label obj = ..

+0

hmmmm ... muss über die Konsequenzen nachdenken, die die Idee der Implementierung von createEditor in Element und Unterklassen haben würde ... in einem ersten Fall hört sich das nicht nach einer schlechten Idee an. und in meiner Situation könnte ich es so benutzen. Aber was ist, wenn Sie diese statische Nutzungsklasse immer noch aus Trennungsgründen trennen möchten? Wie bestimmt Java in meinem Fall, welche Methode aufgerufen wird? Nennt es immer das allgemeinste? Gibt es einen Weg, um es als den spezifischsten zu bezeichnen? – Atmocreations

+0

aktualisierte meine Antwort. und sehen Sie auch die Antworten anderer für das genaue Verhalten. – Bozho

+0

gesehen, thx. Nun ... das Problem ist, dass ich das Ding nicht direkt vor dem Aufruf der Methode in ein Label schreiben möchte. Ansonsten könnte ich direkt Methoden wie createLabelEditor (Label l), createImageEditor (Image i) usw. erstellen. Dies würde die Methode mit Element als Parameter überflüssig machen. – Atmocreations

0

Da Sie wahrscheinlich tun:

Element element = new Label(); 

Es wird vom Compiler bestimmt.

+0

naja, indirekt gesehen (je nach Situation verschiedene Methoden aufrufen) mache ich das, ja. Kommt es wirklich auf den deklarierten Typ des var 'element' an, um zu bestimmen, welche Methode wirklich aufgerufen wird? Wird nicht die Methode mit dem "echten" Typ (Label) aufgerufen?Und wenn nicht, warum? – Atmocreations

2

Das hat wirklich wenig mit Generika zu tun, und alles, was mit Methodenüberladung zu tun hat. In Java wird die aufgerufene Methodensignatur zum Zeitpunkt der Kompilierung ermittelt, nicht zur Laufzeit. Sie müssen also zur Laufzeit prüfen und umwandeln.

diesen So ersetzen:

Element label = getLabel(); 
AbstractPropertyEditor<?> editor = createEditor(label); 

mit diesem:

Element label = getLabel(); 
AbtractPropertyEditor<?> editor; 
if(label instanceof Label) { 
     editor = createEditor((Label) label); 
} else { 
     editor = createEditor(label); 
} 

Der anderen (Standard/besser) Weg, um dieses Problem behebt den createEditor zu haben ist (Element) Methode, um die Art zu überprüfen und Rufen Sie mit einem Cast die korrekte überladene Methode für Subtypen auf. Sie werden jedoch ein Problem mit Ihren Rückgabeparametern haben, wenn Sie dies für die deklarierten Methoden tun.

+0

Danke für die gute Antwort, aber ich möchte 'instanceof' wo immer möglich vermeiden. Daher ist dies für mich keine Option. – Atmocreations

+0

@Atmocreations, dann schlage ich vor, dass Sie nicht Methode Überladung mit Super-und Subtypen als Parameter verwenden. Ein solches Muster führt unweigerlich zum Beispiel und zum Gießen. – Yishai

1

Von der Java Language Specification:

Wenn eine Methode aufgerufen wird (§15.12), die Anzahl der tatsächlichen Argumente (und alle explizite Typargumente) und die Kompilierzeittypen der Argumente werden verwendet, zur Kompilierzeit, bestimmen die Signatur der Methode , die aufgerufen wird (§15.12.2). Wenn die Methode, die aufgerufen wird, werden, um eine Instanz ist Verfahren, die tatsächliche Methode aufgerufen wird zur Laufzeit , unter Verwendung einer dynamischen Methode lookup (§15.12.4) bestimmt werden.

+0

thx. aber obwohl dies absolut richtig ist, hilft es mir weder mit dem aktuellen Problem, noch erklärt es, wie java bestimmt, welche Methode am Ende wirklich aufgerufen wird. – Atmocreations

+0

@Atmocreations: Ich bitte um Unterschiede, es wird klar gesagt, dass im Fall von Nicht-Instanz-Methoden die aufgerufene Methode diejenige ist, die den Typen der Argumente zur Kompilierungszeit entspricht. Da in Ihrem Fall das erste Element aufgerufen wird, bedeutet dies, dass Sie die Methode zum Kompilieren mit einem Element aufrufen. – JRL

+0

Nun ... richtig, Entschuldigung. Ich muss zugeben, dass ich es noch nicht so gesehen habe. – Atmocreations

0

Dies ist ein Beispiel für überladene Methoden. Obwohl das eigentliche Objekt zur Laufzeit ein Label und kein Element ist, wird die Auswahl der überladenen Methode (dh die Signatur der Methode ) zur Laufzeit NICHT dynamisch festgelegt. Der Referenztyp (nicht der Objekttyp) bestimmt, welche überladene Methode aufgerufen wird!

Beispiel

public class Car {  
} 

public class Toyota extends Car {  
} 

public class MyCar { 

    public void run(Car c) { 
     System.out.println("Run any Car"); 
    } 

    public void run(Toyota t) { 
     System.out.println("Run Toyota Car"); 
    } 

    public static void main(String[] args) { 
     MyCar myCar = new MyCar(); 

     Car c1 = new Car(); 
     myCar.run(c1); // Output: Run any Car 

     Toyota c2 = new Toyota(); 
     myCar.run(c2); // Output: Run Toyota Car 

     Car c3 = new Toyota(); 
     myCar.run(c3); // Output: Run any Car  
    } 
} 

also in Ihrem Fall

Element obj1 = new Label(); 
Dispatcher.createEditor(obj); // Method with Element argument is called 
           // as you are passing Element 

Label obj2 = new Label(); 
Dispatcher.createEditor(obj); // Method with Label argument is called 
           // as you are passing Label 

Auf anderer Note, überschriebene Methode Aufruf geschieht zur Laufzeit und es hängt von Objekttyp (in anderen Worten, die Art der tatsächliche Instanz auf dem Heap)

Verwandte Themen