TL; DR, il s'agit d'un bogue du compilateur.
Il n'y a aucune règle qui donnerait la priorité à une méthode applicable particulière lorsqu'elle est héritée ou à une méthode par défaut. Fait intéressant, lorsque je change le code en
interface ConsumerOne<T> {
void accept(T a);
}
interface ConsumerTwo<T> {
void accept(T a);
}
interface CustomIterable<T> extends Iterable<T> {
void forEach(ConsumerOne<? super T> c); //overload
void forEach(ConsumerTwo<? super T> c); //another overload
}
l' iterable.forEach((A a) -> aList.add(a));
instruction produit une erreur dans Eclipse.
Puisqu'aucune propriété de la forEach(Consumer<? super T) c)
méthode de l' Iterable<T>
interface n'a changé lors de la déclaration d'une autre surcharge, la décision d'Eclipse de sélectionner cette méthode ne peut pas (de manière cohérente) être basée sur une propriété de la méthode. C'est toujours la seule méthode héritée, toujours la seule default
méthode, toujours la seule méthode JDK, etc. Aucune de ces propriétés ne devrait de toute façon affecter la sélection de la méthode.
Notez que la modification de la déclaration en
interface CustomIterable<T> {
void forEach(ConsumerOne<? super T> c);
default void forEach(ConsumerTwo<? super T> c) {}
}
produit également une erreur «ambiguë», donc le nombre de méthodes surchargées applicables n'a pas d'importance non plus, même lorsqu'il n'y a que deux candidats, il n'y a pas de préférence générale vers les default
méthodes.
Jusqu'à présent, le problème semble se poser lorsqu'il existe deux méthodes applicables et qu'une default
méthode et une relation d'héritage sont impliquées, mais ce n'est pas le bon endroit pour creuser davantage.
Mais il est compréhensible que les constructions de votre exemple puissent être gérées par différents codes d'implémentation dans le compilateur, l'un présentant un bogue tandis que l'autre ne le fait pas.
a -> aList.add(a)
est une expression lambda typée implicitement , qui ne peut pas être utilisée pour la résolution de surcharge. En revanche, (A a) -> aList.add(a)
est une expression lambda explicitement typée qui peut être utilisée pour sélectionner une méthode correspondante parmi les méthodes surchargées, mais cela n'aide pas ici (ne devrait pas aider ici), car toutes les méthodes ont des types de paramètres avec exactement la même signature fonctionnelle .
À titre de contre-exemple, avec
static void forEach(Consumer<String> c) {}
static void forEach(Predicate<String> c) {}
{
forEach(s -> s.isEmpty());
forEach((String s) -> s.isEmpty());
}
les signatures fonctionnelles diffèrent, et l'utilisation d'une expression lambda de type explicite peut en effet aider à sélectionner la bonne méthode tandis que l'expression lambda implicitement typée n'aide pas, donc forEach(s -> s.isEmpty())
produit une erreur de compilation. Et tous les compilateurs Java sont d'accord là-dessus.
Notez qu'il aList::add
s'agit d'une référence de méthode ambiguë, car la add
méthode est également surchargée, elle ne peut donc pas aider à sélectionner une méthode, mais les références de méthode peuvent de toute façon être traitées par un code différent. Passer à un sans ambiguïté aList::contains
ou passer List
à Collection
, pour rendre l' add
ambiguïté, n'a pas changé le résultat dans mon installation Eclipse (j'ai utilisé 2019-06
).