โปรดแสดงตัวอย่างที่ดีสำหรับความแปรปรวนร่วมและความแตกต่างใน Java
โปรดแสดงตัวอย่างที่ดีสำหรับความแปรปรวนร่วมและความแตกต่างใน Java
คำตอบ:
ความแปรปรวนร่วม:
class Super {
Object getSomething(){}
}
class Sub extends Super {
String getSomething() {}
}
Sub # getSomething เป็น covariant เนื่องจากส่งคืนคลาสย่อยของประเภทผลตอบแทนของ Super # getSomething (แต่เติมเต็มสัญญาของ Super.getSomething ())
ความแตกต่าง
class Super{
void doSomething(String parameter)
}
class Sub extends Super{
void doSomething(Object parameter)
}
Sub # doSomething ไม่แปรผันเนื่องจากใช้พารามิเตอร์ของซูเปอร์คลาสของพารามิเตอร์ของ Super # doSomething (แต่อีกครั้งเติมเต็มสัญญาของ Super # doSomething)
หมายเหตุ: ตัวอย่างนี้ใช้ไม่ได้ใน Java คอมไพเลอร์ Java จะโอเวอร์โหลดและไม่แทนที่ doSomething () - Method ภาษาอื่น ๆ สนับสนุนรูปแบบความขัดแย้งนี้
Generics
สิ่งนี้เป็นไปได้สำหรับ Generics:
List<String> aList...
List<? extends Object> covariantList = aList;
List<? super String> contravariantList = aList;
ตอนนี้คุณสามารถเข้าถึงวิธีการทั้งหมดcovariantList
ที่ไม่ใช้พารามิเตอร์ทั่วไป (เนื่องจากต้องเป็น "ขยายวัตถุ") แต่ getters จะทำงานได้ดี (เนื่องจากวัตถุที่ส่งคืนจะเป็นประเภท "วัตถุ" เสมอ)
สิ่งที่ตรงกันข้ามเป็นจริงสำหรับcontravariantList
: คุณสามารถเข้าถึงเมธอดทั้งหมดด้วยพารามิเตอร์ทั่วไป (คุณรู้ว่าต้องเป็นซูเปอร์คลาสของ "สตริง" ดังนั้นคุณจึงสามารถส่งผ่านได้เสมอ) แต่ไม่มีตัวรับ (ประเภทที่ส่งคืนอาจเป็นซุปเปอร์ไทป์อื่น ๆ ของสตริง )
ความแปรปรวนร่วม: Iterable และ Iterator การกำหนดตัวแปรร่วมIterable
หรือIterator
. Iterator<? extends T>
สามารถนำมาใช้เช่นเดียวกับที่Iterator<T>
- สถานที่เดียวที่พารามิเตอร์ชนิดปรากฏเป็นประเภทผลตอบแทนจากวิธีการเพื่อที่จะสามารถได้อย่างปลอดภัยขึ้นโยนnext
T
แต่ถ้าคุณมีการS
ขยายT
คุณสามารถกำหนดให้Iterator<S>
กับตัวแปรประเภทIterator<? extends T>
ได้ ตัวอย่างเช่นหากคุณกำลังกำหนดวิธีการค้นหา:
boolean find(Iterable<Object> where, Object what)
คุณจะไม่สามารถเรียกมันด้วยList<Integer>
และ5
ดังนั้นจึงนิยามได้ดีกว่าว่า
boolean find(Iterable<?> where, Object what)
Contra-variance: ตัวเปรียบเทียบ มันมักจะทำให้รู้สึกถึงการใช้งานเพราะมันสามารถนำมาใช้เช่นเดียวกับที่Comparator<? super T>
Comparator<T>
พารามิเตอร์ type ปรากฏเป็นcompare
ประเภทพารามิเตอร์ method เท่านั้นดังนั้นจึงT
สามารถส่งผ่านไปได้อย่างปลอดภัย ตัวอย่างเช่นหากคุณมีDateComparator implements Comparator<java.util.Date> { ... }
และต้องการจัดเรียงไฟล์List<java.sql.Date>
ด้วยตัวเปรียบเทียบนั้น ( java.sql.Date
เป็นคลาสย่อยของjava.util.Date
) คุณสามารถทำได้ด้วย:
<T> void sort(List<T> what, Comparator<? super T> how)
แต่ไม่ใช่ด้วย
<T> void sort(List<T> what, Comparator<T> how)
ดูที่หลักการทดแทน Liskov มีผลถ้าคลาส B ขยายคลาส A คุณควรจะใช้ B ได้ทุกเมื่อที่ต้องการ A
contra variant
พูด ไม่สามารถถูกแทนที่ด้วยsuper.doSomething("String")
sub.doSomething(Object)