TL; DR นี่เป็นข้อผิดพลาดของคอมไพเลอร์
ไม่มีกฎที่จะให้ความสำคัญกับวิธีการเฉพาะเมื่อมีการสืบทอดหรือวิธีการเริ่มต้น ที่น่าสนใจเมื่อฉันเปลี่ยนรหัสเป็น
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
}
iterable.forEach((A a) -> aList.add(a));คำสั่งผลิตข้อผิดพลาดใน Eclipse
เนื่องจากไม่มีการเปลี่ยนแปลงคุณสมบัติของforEach(Consumer<? super T) c)เมธอดจากIterable<T>อินเตอร์เฟสเมื่อประกาศโอเวอร์โหลดอื่นการตัดสินใจของ Eclipse เพื่อเลือกวิธีนี้จึงไม่สามารถ (สม่ำเสมอ) ตามคุณสมบัติใด ๆ ของเมธอด มันยังคงเป็นวิธีการสืบทอดเท่านั้นยังคงเป็นdefaultวิธีเดียวยังคงเป็นวิธี JDK เท่านั้นและอื่น ๆ คุณสมบัติเหล่านี้ไม่ควรส่งผลกระทบต่อการเลือกวิธีการต่อไป
โปรดทราบว่าการเปลี่ยนการประกาศเป็น
interface CustomIterable<T> {
void forEach(ConsumerOne<? super T> c);
default void forEach(ConsumerTwo<? super T> c) {}
}
ยังก่อให้เกิดข้อผิดพลาด“ กำกวม” ดังนั้นจำนวนวิธีการโอเวอร์โหลดที่เกี่ยวข้องจึงไม่สำคัญเช่นกันแม้ว่าจะมีผู้สมัครเพียงสองคนก็ตามก็ไม่มีdefaultวิธีการทั่วไปที่ชอบ
จนถึงตอนนี้ดูเหมือนว่าปัญหาจะปรากฏขึ้นเมื่อมีวิธีการที่ใช้ได้สองวิธีและdefaultวิธีการและความสัมพันธ์ในการสืบทอดเกี่ยวข้อง แต่นี่ไม่ใช่สถานที่ที่เหมาะสมที่จะขุดต่อไป
แต่เป็นที่เข้าใจได้ว่าการสร้างตัวอย่างของคุณอาจได้รับการจัดการโดยรหัสการใช้งานที่แตกต่างกันในคอมไพเลอร์หนึ่งแสดงข้อผิดพลาดในขณะที่อื่น ๆ ไม่ได้
a -> aList.add(a)เป็นนิพจน์แลมบ์ดาที่พิมพ์โดยปริยายซึ่งไม่สามารถใช้สำหรับการแก้ปัญหาการโอเวอร์โหลด ในทางตรงกันข้าม(A a) -> aList.add(a)เป็นการแสดงออกแลมบ์ดาที่พิมพ์อย่างชัดเจนซึ่งสามารถใช้เพื่อเลือกวิธีการจับคู่จากวิธีโอเวอร์โหลด แต่มันไม่ได้ช่วยที่นี่ (ไม่ควรช่วยที่นี่) เนื่องจากวิธีการทั้งหมดมีประเภทพารามิเตอร์ที่มีลายเซ็นการทำงานเหมือนกันทุกประการ .
เป็นตัวอย่างเคาน์เตอร์ด้วย
static void forEach(Consumer<String> c) {}
static void forEach(Predicate<String> c) {}
{
forEach(s -> s.isEmpty());
forEach((String s) -> s.isEmpty());
}
ลายเซ็นการทำงานแตกต่างกันและการใช้แลมบ์ดานิพจน์ชนิดที่แน่นอนสามารถช่วยเลือกวิธีการที่เหมาะสมในขณะที่การแสดงออกแลมบ์ดาที่พิมพ์โดยปริยายไม่ได้ช่วยอะไรforEach(s -> s.isEmpty())เลย และคอมไพเลอร์ Java ทั้งหมดเห็นด้วยกับเรื่องนี้
โปรดทราบว่าaList::addนี่คือการอ้างอิงวิธีการที่คลุมเครือเนื่องจากaddวิธีการดังกล่าวมีมากเกินไปดังนั้นจึงไม่สามารถช่วยเลือกวิธีได้ แต่การอ้างอิงวิธีการอาจได้รับการประมวลผลด้วยรหัสที่แตกต่างกันอยู่แล้ว การเปลี่ยนเป็นการใช้งานที่ไม่คลุมเครือaList::containsหรือเปลี่ยนListไปใช้Collectionเพื่อให้เกิดความaddกำกวมไม่ได้เปลี่ยนผลลัพธ์ในการติดตั้ง Eclipse ของฉัน (ฉันใช้2019-06)