Référence est ambiguë avec les génériques
Je suis tout à fait avoir un cas délicat ici avec les médicaments génériques et de la surcharge de méthode. Découvrez cette classe exemple:
public class Test {
public <T> void setValue(Parameter<T> parameter, T value) {
}
public <T> void setValue(Parameter<T> parameter, Field<T> value) {
}
public void test() {
//This works perfectly. <T> is bound to String
//ambiguity between setValue(.., String) and setValue(.., Field)
//is impossible as String and Field are incompatible
Parameter<String> p1 = getP1();
Field<String> f1 = getF1();
setValue(p1, f1);
//This causes issues. <T> is bound to Object
//ambiguity between setValue(.., Object) and setValue(.., Field)
//is possible as Object and Field are compatible
Parameter<Object> p2 = getP2();
Field<Object> f2 = getF2();
setValue(p2, f2);
}
private Parameter<String> getP1() {...}
private Parameter<Object> getP2() {...}
private Field<String> getF1() {...}
private Field<Object> getF2() {...}
}
L'exemple ci-dessus compile parfaitement dans Eclipse (Java 1.6), mais pas avec la Fourmi commande javac (ou avec le JDK de commande de javac), où je reçois ce type de message d'erreur sur la deuxième invocation de setValue
:
référence à setValue est ambigu,
les deux méthode
setValue(org.jooq.Paramètre,T)
dans l'Essai et la méthode
setValue(org.jooq.Paramètre,org.jooq.Champ)
en Test match
Selon le cahier des charges et à ma compréhension de la façon dont le compilateur Java fonctionne, le plus spécifique de la méthode doit toujours être choisi: http://java.sun.com/docs/books/jls/third_edition/html/expressions.html#20448
Dans tous les cas, même si <T>
est lié à Object
, ce qui le rend à la fois setValue
méthodes acceptables candidats pour l'invocation, l'un avec le Field
paramètre semble toujours être plus précis. Et cela fonctionne dans Eclipse, mais pas avec le JDK du compilateur.
Mise à JOUR:
Comme cela, il serait de travailler à la fois dans Eclipse et avec le JDK compilateur (avec rawtypes mises en garde, bien sûr). Je comprends que les règles spécifiées dans les spécifications sont assez spéciales, lorsque les génériques sont impliqués. Mais je trouve cela plutôt déroutant:
public <T> void setValue(Parameter<T> parameter, Object value) {
}
//Here, it's easy to see that this method is more specific
public <T> void setValue(Parameter<T> parameter, Field value) {
}
Mise à JOUR 2:
Même avec les génériques, je peux créer cette solution de contournement, où j'ai éviter le type <T>
être lié à des Object
à setValue
invocation du temps, en ajoutant des supplémentaires de, sans ambiguïté indirection appelé setValue0
. Cela me fait penser que la liaison de T
à Object
est vraiment ce qui est à l'origine de tous les problèmes ici:
public <T> void setValue(Parameter<T> parameter, T value) {
}
public <T> void setValue(Parameter<T> parameter, Field<T> value) {
}
public <T> void setValue0(Parameter<T> parameter, Field<T> value) {
//This call wasn't ambiguous in Java 7
//It is now ambiguous in Java 8!
setValue(parameter, value);
}
public void test() {
Parameter<Object> p2 = p2();
Field<Object> f2 = f2();
setValue0(p2, f2);
}
Suis-je malentendu quelque chose ici? Est-il connu du compilateur bug lié à cela? Ou est-il une solution/compilateur paramètre pour m'aider?
Suivi:
Pour ceux qui sont intéressés, j'ai déposé un rapport de bug à la fois à Oracle et Eclipse. Oracle a accepté le bug, jusqu'à présent, Eclipse a analysé et l'a rejeté! Il semble que si mon intuition est bonne et c'est un bug dans javac
- http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=7031404
- https://bugs.eclipse.org/bugs/show_bug.cgi?id=340506
- https://bugs.eclipse.org/bugs/show_bug.cgi?id=469014 (un nouveau problème dans Eclipse Mars)
- je pense que, ant est pointant vers les différentes compilateur, ce qui n'est pas une release candidate.
- ant utilise le JDK est
javac
compilateur. C'est Eclipse qui peut avoir sa propre...
Vous devez vous connecter pour publier un commentaire.
JDK est droit. La 2e méthode n'est pas plus précis que le 1er. De JLS3#15.12.2.5
"Le secteur informel de l'intuition est qu'une méthode est plus spécifique que l'autre, si toute invocation gérées par la première méthode peut être transmise à l'autre sans un moment de la compilation type d'erreur."
Ce n'est clairement pas le cas ici. Je l'ai souligné toute invocation. La propriété d'une méthode plus spécifique que l'autre purement repose sur les deux méthodes elles-mêmes; elle ne change pas par invocation.
Analyse formelle sur votre problème: est-m2 plus spécifique que la m1?
D'abord, le compilateur doit en déduire R à partir de la première contraintes:
Le résultat est
R=V
, de par les règles d'inférence dans 15.12.2.7Maintenant nous substituer
R
et vérifier le sous-type de relationsLa 2e ligne ne tient pas, par sous-typage des règles en 4.10.2. Afin de m2 n'est pas plus spécifique que la m1.
V
n'est pasObject
dans cette analyse, l'analyse considère toutes les valeurs possibles deV
.Je suggère d'utiliser différents noms de méthode. La surcharge n'est jamais une nécessité.
Cela semble être un important bug dans Eclipse. La spec assez indique clairement que le type de variables ne sont pas remplacés dans cette étape. Eclipse ne semble variable de type substitution d'abord, puis méthode de contrôle de la spécificité de la relation.
Si un tel comportement est plus "sensible" dans certains exemples, il n'est pas dans d'autres exemples. Dire,
"Intuitivement", et officiellement par spec, le m2 est plus spécifique que la m1, et le test s'imprime "2". Toutefois, si la substitution
T=Integer
est faite en premier, les deux méthodes ne sont pas identiques!pour la mise à Jour 2
Ici, m1 n'est pas applicable pour l'invocation de méthode s4, de sorte m2 est le seul choix.
Par 15.12.2.2, pour voir si m1 est applicable pour les s4, tout d'abord, l'inférence de type est effectué, à la conclusion que R=T; on vérifie ensuite
Ai :< Si
, ce qui conduit àField<T> <: T
, ce qui est faux.Ceci est cohérent avec l'analyse précédente - si m1 est applicable à s4, toute invocation traitées par m2 (essentiellement les mêmes que s4) peuvent être traitées par m1, ce qui signifie m2 serait plus précis que le m1, ce qui est faux.
dans un type paramétré
Considérons le code suivant
Cette compile sans problème. Par 4.5.2, les types de méthodes dans
PF<Object>
sont des méthodes dansPF<T>
avec la substitutionT=Object
. Qui est, les méthodes depf2
sontLa 2e méthode est plus spécifique que le 1er.
V
être lié à desObject
n'a pas d'importance que vous dites, alors pourquoi est-ce mise à JOUR 2 dans ma question compilable?Object
comme lié pourT
il existe une ambiguïté selon les spécifications. Mais c'est mon très informelle et intuitive avis, comme un compilateur-anti-expert :-).<T extends Object>
et<T extends Number>
. Il choisitm2
surm1
, sans aucune erreur...<<
moyenne dans l'inférence de contexte?Ma conjecture est que le compilateur fait une surcharge de la méthode de résolution par JLS, Section 15.12.2.5.
Pour cette Section, le compilateur utilise forte de sous-typage (ne permettant pas à tout unchecked conversion), de sorte que,
T value
devientObject value
etField<T> value
devientField<Object> value
. Les règles suivantes s'appliquent:(Voir point 2). Depuis
Field<Object>
est un sous-type deObject
alors le plus spécifique de la méthode se trouve. Champf2
correspond à la fois à des méthodes de la vôtre (à cause du point 2 ci-dessus) et la rend ambiguë.Pour
String
etField<String>
, il n'y a pas de sous-type de la relation entre les deux.PS. C'est ma compréhension des choses, ne pas le citer comme casher.
String
cas de travail?T
dans le compilateur de message d'erreur, siT
ont déjà été effacées? En outre,Object
etField
sont encore des types distincts, même après l'effacementModifier: Cette réponse est fausse. Jetez un oeil à accepté de répondre.
Je pense que le problème vient de ce: compilateur ne pas voir le type de f2 (c'est à dire le Terrain) et le type inféré du paramètre formel (c'est à dire de Champ -> Champ) que le même type.
En d'autres termes, il ressemble type de f2 (Champ) est considéré comme un sous-type du type de paramètre formel de Champ (Domaine). Depuis le Champ est le même type d'un sous-type de l'Objet, le compilateur ne peut pas choisir une méthode plutôt qu'une autre.
Modifier: Permettez-moi de développer ma déclaration un peu
Les deux méthodes sont applicable et il semble que la Phase 1: Identifier Correspondant Arité de Méthodes Applicables par sous-typage est utilisé pour décider de la méthode à appeler et que les règles de Le choix de la Méthode Spécifique appliquée, mais a échoué pour une raison de choisir la deuxième méthode, plus de premier.
Phase 1 section utilise cette notation:
X <: S
(X est le sous-type de S). Basé sur ma compréhension de<:
,X <: X
est une expression valide, c'est à dire la<:
n'est pas stricte et comprend le type lui-même (X est le sous-type de X) dans ce contexte. C'est ce qui explique le résultat de la Phase 1: les deux méthodes sont choisis comme candidats, depuisField<Object> <: Object
etField<Object> <: Field<Object>
.Le choix de la Méthode Spécifique section utilise la même notation pour dire qu'une méthode est plus spécifique que l'autre. La partie intéressante du paragraphe qui commence par "Un fixe-arité de la méthode de membre nommé m est plus spécifique que l'autre membre...". Il a, entre autres choses:
Cela me fait penser que dans notre cas de la deuxième méthode doit être choisis sur la première, parce que la suite est titulaire d':
Parameter<Object> <: Parameter<Object>
Field<Object> <: Object
alors que l'inverse ne tient pas en raison de
Object <: Field<Object>
être faux (l'Objet n'est pas un sous-type de Champ).Remarque: Dans le cas des exemples de Chaîne, la Phase 1 s'il suffit de choisir la seule méthode applicable: le deuxième.
Donc, pour répondre à tes questions: je pense que c'est un bug dans le compilateur de mise en œuvre. Eclipse a c'est propre différentiels compilateur, ce qui n'a pas ce bug, il me semble.