TL; DR, đây là một lỗi biên dịch.
Không có quy tắc nào được ưu tiên cho một phương thức áp dụng cụ thể khi nó được kế thừa hoặc một phương thức mặc định. Thật thú vị, khi tôi thay đổi mã thành
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
}
các iterable.forEach((A a) -> aList.add(a));
tuyên bố tạo ra một lỗi trong Eclipse.
Vì không có thuộc tính của forEach(Consumer<? super T) c)
phương thức từIterable<T>
giao diện thay đổi khi khai báo một tình trạng quá tải khác, nên quyết định chọn phương thức này của Eclipse không thể (nhất quán) dựa trên bất kỳ thuộc tính nào của phương thức. Đây vẫn là phương thức được kế thừa duy nhất, vẫn là default
phương thức duy nhất , vẫn là phương thức JDK duy nhất, v.v. Cả hai thuộc tính này sẽ không ảnh hưởng đến việc lựa chọn phương thức nào.
Lưu ý rằng thay đổi khai báo thành
interface CustomIterable<T> {
void forEach(ConsumerOne<? super T> c);
default void forEach(ConsumerTwo<? super T> c) {}
}
cũng tạo ra một lỗi mập mờ mơ hồ, do đó, số lượng phương thức quá tải có thể áp dụng cũng không thành vấn đề, ngay cả khi chỉ có hai ứng cử viên, không có ưu tiên chung nào đối với default
các phương thức.
Cho đến nay, vấn đề dường như xuất hiện khi có hai phương pháp áp dụng và default
phương pháp và mối quan hệ thừa kế có liên quan, nhưng đây không phải là nơi thích hợp để đào sâu hơn.
Nhưng có thể hiểu rằng các cấu trúc của ví dụ của bạn có thể được xử lý bằng các mã triển khai khác nhau trong trình biên dịch, một cấu trúc thể hiện một lỗi trong khi cái kia thì không.
a -> aList.add(a)
là một biểu thức lambda được gõ ngầm , không thể được sử dụng cho độ phân giải quá tải. Ngược lại, (A a) -> aList.add(a)
là một biểu thức lambda được gõ rõ ràng có thể được sử dụng để chọn một phương thức khớp từ các phương thức bị quá tải, nhưng nó không giúp ích ở đây (không nên trợ giúp ở đây), vì tất cả các phương thức đều có các loại tham số có cùng chữ ký chức năng .
Như một ví dụ ngược lại, với
static void forEach(Consumer<String> c) {}
static void forEach(Predicate<String> c) {}
{
forEach(s -> s.isEmpty());
forEach((String s) -> s.isEmpty());
}
các chữ ký chức năng khác nhau và sử dụng biểu thức lambda loại rõ ràng thực sự có thể giúp chọn đúng phương thức trong khi biểu thức lambda được gõ ngầm không giúp ích gì, vì vậy forEach(s -> s.isEmpty())
tạo ra lỗi trình biên dịch. Và tất cả các trình biên dịch Java đều đồng ý về điều đó.
Lưu ý rằng đó aList::add
là một tham chiếu phương thức mơ hồ, vì add
phương thức cũng bị quá tải, do đó, nó cũng không thể giúp chọn một phương thức, nhưng dù sao các tham chiếu phương thức có thể được xử lý bởi các mã khác nhau. Chuyển sang một cách rõ ràng aList::contains
hoặc thay đổi List
thành Collection
, để add
rõ ràng, không thay đổi kết quả trong cài đặt Eclipse của tôi (tôi đã sử dụng 2019-06
).