TL; DR, dies ist ein Compiler-Fehler.
Es gibt keine Regel, die einer bestimmten anwendbaren Methode Vorrang einräumt, wenn sie vererbt wird, oder einer Standardmethode. Interessanterweise, wenn ich den Code auf ändere
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
}
Die iterable.forEach((A a) -> aList.add(a));
Anweisung erzeugt einen Fehler in Eclipse.
Da sich beim Deklarieren einer weiteren Überladung keine Eigenschaft der forEach(Consumer<? super T) c)
Methode über die Iterable<T>
Schnittstelle geändert hat, kann die Entscheidung von Eclipse, diese Methode auszuwählen, nicht (konsistent) auf einer Eigenschaft der Methode basieren. Es ist immer noch die einzige geerbte Methode, immer noch die einzige default
Methode, immer noch die einzige JDK-Methode und so weiter. Keine dieser Eigenschaften sollte sich ohnehin auf die Methodenauswahl auswirken.
Beachten Sie, dass Sie die Deklaration in ändern
interface CustomIterable<T> {
void forEach(ConsumerOne<? super T> c);
default void forEach(ConsumerTwo<? super T> c) {}
}
erzeugt auch einen "mehrdeutigen" Fehler, so dass die Anzahl der anwendbaren überladenen Methoden ebenfalls keine Rolle spielt, selbst wenn es nur zwei Kandidaten gibt, gibt es keine allgemeine Präferenz für default
Methoden.
Bisher scheint das Problem aufzutreten, wenn zwei anwendbare Methoden vorhanden sind und eine default
Methode und eine Vererbungsbeziehung beteiligt sind, aber dies ist nicht der richtige Ort, um weiter zu graben.
Es ist jedoch verständlich, dass die Konstrukte Ihres Beispiels möglicherweise von unterschiedlichem Implementierungscode im Compiler verarbeitet werden, wobei einer einen Fehler aufweist, der andere jedoch nicht.
a -> aList.add(a)
ist ein implizit typisierter Lambda-Ausdruck, der nicht für die Überlastungsauflösung verwendet werden kann. Im Gegensatz dazu (A a) -> aList.add(a)
handelt es sich um einen explizit typisierten Lambda-Ausdruck, mit dem eine übereinstimmende Methode aus den überladenen Methoden ausgewählt werden kann. Dies hilft hier jedoch nicht (sollte hier nicht helfen), da alle Methoden Parametertypen mit genau derselben funktionalen Signatur haben .
Als Gegenbeispiel mit
static void forEach(Consumer<String> c) {}
static void forEach(Predicate<String> c) {}
{
forEach(s -> s.isEmpty());
forEach((String s) -> s.isEmpty());
}
Die funktionalen Signaturen unterscheiden sich, und die Verwendung eines explizit eingegebenen Lambda-Ausdrucks kann in der Tat bei der Auswahl der richtigen Methode hilfreich sein, während der implizit typisierte Lambda-Ausdruck nicht hilfreich ist und daher forEach(s -> s.isEmpty())
einen Compilerfehler erzeugt. Und alle Java-Compiler sind sich einig.
Beachten Sie, dass dies aList::add
eine mehrdeutige Methodenreferenz ist, da die add
Methode ebenfalls überladen ist, sodass sie auch bei der Auswahl einer Methode helfen kann. Methodenreferenzen werden jedoch möglicherweise trotzdem von einem anderen Code verarbeitet. Das Wechseln zu einer eindeutigen aList::contains
oder das Ändern List
zu Collection
, um add
eindeutig zu machen , hat das Ergebnis in meiner Eclipse-Installation (die ich verwendet habe 2019-06
) nicht geändert .