J'expérimente ce code:
interface Callee {
public void foo(Object o);
public void foo(String s);
public void foo(Integer i);
}
class CalleeImpl implements Callee
public void foo(Object o) {
logger.debug("foo(Object o)");
}
public void foo(String s) {
logger.debug("foo(\"" + s + "\")");
}
public void foo(Integer i) {
logger.debug("foo(" + i + ")");
}
}
Callee callee = new CalleeImpl();
Object i = new Integer(12);
Object s = "foobar";
Object o = new Object();
callee.foo(i);
callee.foo(s);
callee.foo(o);
Cela s'imprime foo(Object o)
trois fois. Je m'attends à ce que la sélection de la méthode prenne en considération le type de paramètre réel (et non déclaré). Est-ce que je manque quelque chose? Existe-t-il un moyen de modifier ce code pour qu'il s'imprime foo(12)
, foo("foobar")
et foo(Object o)
?
foo(Object)
. Lors de l'exécution, la classe de l' objet sur laquelle la méthode est appelée détermine quelle implémentation de cette méthode est appelée, en tenant compte du fait qu'il peut s'agir d'une instance d'une sous-classe du type déclaré qui remplace la méthode.Comme mentionné précédemment, la résolution de surcharge est effectuée au moment de la compilation.
Java Puzzlers a un bel exemple pour cela:
Puzzle 46: Le cas du constructeur déroutant
Ce puzzle vous présente deux constructeurs déroutants. La méthode main invoque un constructeur, mais lequel? La sortie du programme dépend de la réponse. Qu'est-ce que le programme imprime, ou est-il même légal?
Solution 46: Cas du constructeur déroutant
... Le processus de résolution de surcharge de Java fonctionne en deux phases. La première phase sélectionne toutes les méthodes ou constructeurs accessibles et applicables. La deuxième phase sélectionne le plus spécifique des méthodes ou des constructeurs sélectionnés dans la première phase. Une méthode ou un constructeur est moins spécifique qu'un autre s'il peut accepter des paramètres passés à l'autre [JLS 15.12.2.5].
Dans notre programme, les deux constructeurs sont accessibles et applicables. Le constructeur Confusing (Object) accepte tout paramètre passé à Confusing (double []) , donc Confusing (Object) est moins spécifique. (Chaque double tableau est un objet , mais tous les objets ne sont pas un double tableau .) Le constructeur le plus spécifique est donc Confus (double []) , ce qui explique la sortie du programme.
Ce comportement est logique si vous transmettez une valeur de type double [] ; il est contre-intuitif si vous passez null . La clé pour comprendre ce puzzle est que le test pour lequel la méthode ou le constructeur est le plus spécifique n'utilise pas les paramètres réels : les paramètres apparaissant lors de l'invocation. Ils ne sont utilisés que pour déterminer les surcharges applicables. Une fois que le compilateur a déterminé quelles surcharges sont applicables et accessibles, il sélectionne la surcharge la plus spécifique, en utilisant uniquement les paramètres formels: les paramètres apparaissant dans la déclaration.
Pour appeler le constructeur Confusing (Object) avec un paramètre null , écrivez new Confusing ((Object) null) . Cela garantit que seul Confusing (Object) est applicable. Plus généralement, pour forcer le compilateur à sélectionner une surcharge spécifique, transtypez les paramètres réels en types déclarés des paramètres formels.
la source
La capacité d'envoyer un appel à une méthode en fonction de types d'arguments est appelée répartition multiple . En Java, cela se fait avec le modèle de visiteur .
Cependant, puisque vous avez affaire à
Integer
s etString
s, vous ne pouvez pas facilement incorporer ce modèle (vous ne pouvez tout simplement pas modifier ces classes). Ainsi, un géantswitch
sur le temps d'exécution des objets sera votre arme de choix.la source
En Java, la méthode à appeler (comme la signature de méthode à utiliser) est déterminée au moment de la compilation, elle va donc avec le type de compilation.
Le modèle typique pour contourner ce problème consiste à vérifier le type d'objet dans la méthode avec la signature Object et à déléguer à la méthode avec un cast.
Si vous avez de nombreux types et que cela est ingérable, alors la surcharge de méthode n'est probablement pas la bonne approche, mais la méthode publique devrait simplement prendre Object et implémenter une sorte de modèle de stratégie pour déléguer la gestion appropriée par type d'objet.
la source
J'ai eu un problème similaire en appelant le bon constructeur d'une classe appelée "Parameter" qui pourrait prendre plusieurs types Java de base tels que String, Integer, Boolean, Long, etc. Étant donné un tableau d'objets, je veux les convertir en un tableau de mes objets Parameter en appelant le constructeur le plus spécifique pour chaque objet du tableau d'entrée. Je voulais également définir le paramètre du constructeur (Object o) qui lèverait une IllegalArgumentException. J'ai bien sûr trouvé que cette méthode était invoquée pour chaque objet de mon tableau.
La solution que j'ai utilisée était de rechercher le constructeur par réflexion ...
Aucune vilaine instanceof, instruction de commutation ou modèle de visiteur requis! :)
la source
Java examine le type de référence lorsqu'il tente de déterminer la méthode à appeler. Si vous souhaitez forcer votre code, vous choisissez la `` bonne '' méthode, vous pouvez déclarer vos champs comme des instances du type spécifique:
Vous pouvez également convertir vos paramètres en type de paramètre:
la source
S'il existe une correspondance exacte entre le nombre et les types d'arguments spécifiés dans l'appel de méthode et la signature de méthode d'une méthode surchargée, c'est la méthode qui sera appelée. Vous utilisez des références Object, donc java décide au moment de la compilation que pour Object param, il existe une méthode qui accepte directement Object. Donc, il a appelé cette méthode 3 fois.
la source