TL; DR, questo è un bug del compilatore.
Non esiste una regola che dia la precedenza a un particolare metodo applicabile quando viene ereditato o un metodo predefinito. È interessante notare che quando cambio il codice in
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));istruzione produce un errore in Eclipse.
Poiché nessuna proprietà del forEach(Consumer<? super T) c)metodo Iterable<T>dall'interfaccia è cambiata quando si dichiara un altro sovraccarico, la decisione di Eclipse di selezionare questo metodo non può essere (coerentemente) basata su alcuna proprietà del metodo. È ancora l'unico metodo ereditato, ancora l'unico defaultmetodo, ancora l'unico metodo JDK e così via. Nessuna di queste proprietà dovrebbe comunque influire sulla selezione del metodo.
Si noti che cambiando la dichiarazione in
interface CustomIterable<T> {
void forEach(ConsumerOne<? super T> c);
default void forEach(ConsumerTwo<? super T> c) {}
}
produce anche un errore "ambiguo", quindi anche il numero di metodi sovraccarichi applicabili non ha importanza, anche quando ci sono solo due candidati, non esiste una preferenza generale verso i defaultmetodi.
Finora, il problema sembra apparire quando ci sono due metodi applicabili e defaultsono coinvolti un metodo e una relazione di ereditarietà, ma questo non è il posto giusto per approfondire.
Ma è comprensibile che i costrutti del tuo esempio possano essere gestiti da diversi codici di implementazione nel compilatore, uno che mostra un bug mentre l'altro no.
a -> aList.add(a)è un'espressione lambda tipizzata in modo implicito , che non può essere utilizzata per la risoluzione del sovraccarico. Al contrario, (A a) -> aList.add(a)è un un'espressione lambda tipizzata in modo esplicito che può essere utilizzata per selezionare un metodo corrispondente dai metodi sovraccarichi, ma non aiuta qui (non dovrebbe aiutare qui), poiché tutti i metodi hanno tipi di parametri con esattamente la stessa firma funzionale .
Come controesempio, con
static void forEach(Consumer<String> c) {}
static void forEach(Predicate<String> c) {}
{
forEach(s -> s.isEmpty());
forEach((String s) -> s.isEmpty());
}
le firme funzionali differiscono e l'uso di un'espressione lambda di tipo esplicito può effettivamente aiutare a selezionare il metodo giusto mentre l'espressione lambda tipicamente implicita non aiuta, quindi forEach(s -> s.isEmpty()) produce un errore del compilatore. E tutti i compilatori Java sono d'accordo su questo.
Si noti che si aList::addtratta di un riferimento al metodo ambiguo, poiché anche il addmetodo è sovraccarico, quindi non può essere di aiuto nella selezione di un metodo, ma i riferimenti al metodo potrebbero comunque essere elaborati da un codice diverso. Passare a un non ambiguo aList::containso passare Lista Collection, per renderlo addnon ambiguo, non ha modificato il risultato nella mia installazione di Eclipse (ho usato 2019-06).