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
)