TL; DR, ini adalah bug penyusun.
Tidak ada aturan yang akan diutamakan untuk metode tertentu yang berlaku ketika diwariskan atau metode default. Menariknya, ketika saya mengubah kode ke
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
}
yang iterable.forEach((A a) -> aList.add(a));
pernyataan menghasilkan kesalahan dalam Eclipse.
Karena tidak ada properti forEach(Consumer<? super T) c)
metode dari Iterable<T>
antarmuka berubah ketika menyatakan kelebihan lainnya, keputusan Eclipse untuk memilih metode ini tidak dapat (secara konsisten) didasarkan pada properti metode apa pun. Itu masih satu-satunya metode yang diwariskan, masih satu-satunya default
metode, masih satu-satunya metode JDK, dan seterusnya. Tak satu pun dari properti ini yang akan memengaruhi pemilihan metode.
Perhatikan bahwa mengubah deklarasi menjadi
interface CustomIterable<T> {
void forEach(ConsumerOne<? super T> c);
default void forEach(ConsumerTwo<? super T> c) {}
}
juga menghasilkan kesalahan "ambigu", sehingga jumlah metode kelebihan beban yang berlaku juga tidak masalah, bahkan ketika hanya ada dua kandidat, tidak ada preferensi umum terhadap default
metode.
Sejauh ini, masalah tampaknya muncul ketika ada dua metode yang berlaku dan default
metode dan hubungan warisan yang terlibat, tetapi ini bukan tempat yang tepat untuk menggali lebih jauh.
Tetapi dapat dimengerti bahwa konstruk dari contoh Anda dapat ditangani oleh kode implementasi yang berbeda di kompiler, yang satu menunjukkan bug sementara yang lain tidak.
a -> aList.add(a)
adalah ekspresi lambda yang diketik secara implisit , yang tidak dapat digunakan untuk resolusi kelebihan beban. Sebaliknya, (A a) -> aList.add(a)
adalah ekspresi lambda yang diketik secara eksplisit yang dapat digunakan untuk memilih metode yang cocok dari metode kelebihan beban, tetapi itu tidak membantu di sini (seharusnya tidak membantu di sini), karena semua metode memiliki tipe parameter dengan tanda tangan fungsional yang persis sama .
Sebagai contoh tandingan, dengan
static void forEach(Consumer<String> c) {}
static void forEach(Predicate<String> c) {}
{
forEach(s -> s.isEmpty());
forEach((String s) -> s.isEmpty());
}
tanda tangan fungsional berbeda, dan menggunakan ekspresi lambda tipe eksplisit memang dapat membantu memilih metode yang tepat sedangkan ekspresi lambda yang diketik secara implisit tidak membantu, sehingga forEach(s -> s.isEmpty())
menghasilkan kesalahan kompilator. Dan semua kompiler Java setuju tentang itu.
Perhatikan bahwa aList::add
ini adalah referensi metode yang ambigu, karena add
metode ini kelebihan beban juga, jadi itu juga tidak dapat membantu memilih metode, tetapi referensi metode mungkin akan diproses oleh kode yang berbeda pula. Beralih ke yang ambigu aList::contains
atau berubah List
menjadi Collection
, untuk membuat add
tidak ambigu, tidak mengubah hasil di instalasi Eclipse saya (saya menggunakan 2019-06
).