2010-02-14 9 views
5

J'ai une classe de base appelée Element. D'autres classes (comme Label et Image) étendent cette classe.Priorité aux méthodes surchargées

J'ai maintenant une classe dispatching ayant les méthodes suivantes:

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

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

Si j'ai une instance d'étiquette (qui étend l'élément) et je veux transmettre à createEditor(), pourquoi est la méthode la plus générique (le second) appelé? Ne serait-il pas normal que la méthode (createEditor(Label e)) soit appelée?

J'ai besoin absolument la méthode avec l'élément param pour « attraper » toutes les classes qui a) mettre en œuvre des éléments mais ne disposent pas de leur propre méthode spécifique dans cette classe dispatching ..

J'utilise Java 6, comment "réparer" cela?

Editer: Bon, je dois admettre que ce n'est pas du tout des génériques. Mais c'est là que je l'ai rencontré la première fois.

Merci et salutations

+0

Vous avez l'instance affectée à une variable de type 'Label' pas' Element'? –

+0

(et pas de 'T extends Element' où' T' se trouve être 'Label'?) –

Répondre

6

Pourquoi ne pas:

  • font Element classe abstraite qui fournit un défaut createEditor() mise en œuvre
  • faire Label remplacer le createEditor().

Ainsi, vous n'aurez pas besoin des utilitaires statiques et atteindrez votre objectif.

Si vous avez besoin Element être une interface, puis:

  • définissent createEditor() comme méthodes de Element
  • définir une interface EditorFactory
  • fournissent DefaultEditorFactory et ListEditorFactory
  • utiliser les usines appropriées les réalisateurs de Element:

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

où est instancié le EditorFactory béton soit lors de l'initialisation ou par l'intermédiaire d'une sorte de dependecy-injection. Selon votre question concrète - cela dépend du type que vous avez compilé là-bas. Si vous appelez createEditor(obj) cela dépendra que ce soit Element obj = .. ou Label obj = ..

+0

hmmmm ... il faut penser un instant aux conséquences que l'idée d'implémenter createEditor dans Element et les sous-classes aurait ... dans un premier temps, ça ne sonne pas comme une mauvaise idée. et dans ma situation, je pourrais peut-être l'utiliser de cette façon. Mais que se passe-t-il si vous voulez toujours séparer ces classes d'utilitaires statiques pour des raisons de séparation? Comment Java détermine-t-il dans mon cas la méthode à appeler? Est-ce que ça s'appelle toujours le plus générique? Y at-il un moyen de l'appeler le plus spécifique? – Atmocreations

+0

a mis à jour ma réponse. et voir les réponses des autres pour le comportement exact. – Bozho

+0

l'a vu, merci. Eh bien ... le problème est que je n'aime pas jeter cette chose dans un Label juste avant d'appeler la méthode. Sinon, je pourrais directement créer des méthodes telles que createLabelEditor (Label l), createImageEditor (Image i), etc. Cela annulerait la méthode ayant Element comme paramètre. – Atmocreations

0

Puisque vous faites probablement:

Element element = new Label(); 

Il est déterminé par le compilateur.

+0

bien, vu indirectement (appelant différentes méthodes selon la situation) Je fais ceci, oui. Cela dépend-il vraiment du type déclaré de la variable 'element' pour déterminer quelle méthode est réellement appelée? La méthode avec le type "réel" (Label) n'est-elle pas appelée?Et si non, quelle est la raison pour cela? – Atmocreations

2

Cela a vraiment peu à voir avec les génériques, et tout à voir avec la surcharge des méthodes. En Java, la signature de méthode appelée est déterminée au moment de la compilation, pas au moment de l'exécution, vous devez donc vérifier et lancer au moment de l'exécution.

remplacer donc ceci:

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

Avec ceci:

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

L'autre (plus standard/meilleure) pour résoudre ce problème est d'avoir la méthode createEditor (élément) vérifier le type et appeler avec une distribution la méthode correcte surchargée pour les sous-types. Cependant, vous aurez un problème avec vos paramètres de retour si vous le faites sur les méthodes déclarées.

+0

Merci pour la bonne réponse, mais je voudrais éviter 'instanceof' autant que possible. Par conséquent, ce n'est pas une option pour moi. – Atmocreations

+0

@Atmocreations, alors je vous suggère de ne pas utiliser la méthode surchargée avec super et sous-types comme paramètres. Un tel modèle conduit inévitablement à instanceof et casting. – Yishai

1

De l'Java Language Specification:

Lorsqu'une méthode est invoquée (§15.12), le nombre d'arguments réels (et les arguments de type explicites) et les types de compilation des arguments sont utilisés, au moment de la compilation, à déterminer la signature de la méthode qui sera invoquée (§15.12.2). Si la méthode qui doit être invoqué est une méthode d'instance , la véritable méthode pour être invoqué sera déterminé à l'exécution temps, en utilisant la méthode dynamique recherche (§15.12.4).

+0

thx. mais bien que cela soit absolument correct, cela ne m'aide pas non plus avec le problème actuel et n'explique pas comment java détermine quelle méthode est réellement appelée à la fin. – Atmocreations

+0

@Atmocreations: Je ne suis pas d'accord, il indique clairement que dans le cas de méthodes non-instance, la méthode invoquée sera celle qui correspond aux types des arguments à la compilation. Puisque dans votre cas, c'est l'élément qui est appelé, cela signifie que vous appelez la méthode avec un élément au moment de la compilation. – JRL

+0

Eh bien ... bien, excusez-moi. Je dois admettre que je ne l'ai pas encore vu. – Atmocreations

0

Ceci est un exemple de méthodes surchargées. Même si l'objet réel à l'exécution est une étiquette et non un élément, le choix de la méthode surchargée à appeler (en d'autres termes, la signature de la méthode ) n'est PAS décidé de façon dynamique au moment de l'exécution. Le type de référence (pas le type d'objet) détermine quelle méthode surchargée est appelée!

Exemple

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

Ainsi, dans votre cas

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 

Sur un autre billet, l'invocation de méthode surchargée arrive au moment de l'exécution et cela dépend du type d'objet (autrement dit, le type de instance réelle sur le tas)

Questions connexes