ความแตกต่างระหว่าง <คืออะไร ขยาย Foo> และ <Foo>


20

ฉันดูเหมือนจะมีความเข้าใจผิดเกี่ยวกับความแตกต่างระหว่างและ<Foo> <? extends Foo>จากความเข้าใจของฉันถ้าเรามี

ArrayList<Foo> foos = new ArrayList<>();

สิ่งนี้บ่งชี้ว่าวัตถุประเภทFooสามารถเพิ่มในรายการอาร์เรย์นี้ เนื่องจากคลาสย่อยของFooยังเป็นประเภทFooจึงสามารถเพิ่มได้โดยไม่มีข้อผิดพลาดตามที่แสดงใน

ArrayList<Foo> foos = new ArrayList<>();
foos.add(new Foo());
foos.add(new Bar());

Bar extends Fooที่ไหน

ตอนนี้พูดว่าฉันได้กำหนดไว้foosเป็น

ArrayList<? extends Foo> foos = new ArrayList<>();

some unknown type that extends Fooเข้าใจในปัจจุบันของฉันคือเป็นการแสดงออกที่ว่านี้ ฉันใช้สิ่งนี้เพื่อหมายความว่าวัตถุใด ๆ ที่เป็น subclass ของFooสามารถเพิ่มลงในรายการนี้; หมายความว่ามีความแตกต่างระหว่างไม่มีและArrayList<Foo>ArrayList<? extends Foo>

เพื่อทดสอบสิ่งนี้ฉันพยายามเขียนรหัสต่อไปนี้

ArrayList<? extends Foo> subFoos = new ArrayList<>();
subFoos.add(new Foo());
subFoos.add(new Bar());

แต่ได้รับแจ้งพร้อมกับข้อผิดพลาดในการรวบรวม

no suitable method found for add(Foo)
method java.util.Collection.add(capture#1 of ? extends Foo) is not applicable
(argument mismatch; Foo cannot be converted to capture#1 of ? extends Foo)

no suitable method found for add(Bar)
method java.util.Collection.add(capture#2 of ? extends Bar) is not applicable
(argument mismatch; Bar cannot be converted to capture#2 of ? extends Bar)

จากความเข้าใจปัจจุบันของฉันฉันเห็นได้ว่าเหตุใดฉันจึงไม่สามารถเพิ่มFooรายการลงในรายการ<? extends Foo>เพราะมันไม่ได้เป็นคลาสย่อยของตัวเอง แต่ฉันอยากรู้ว่าทำไมฉันไม่สามารถเพิ่มลงBarในรายการ

รูในความเข้าใจของฉันอยู่ที่ไหน



1
<? extends Foo>เป็นที่เฉพาะเจาะจงและไม่รู้จักFooคลาสที่ขยาย การดำเนินการกับการเรียนนี้เป็นกฎหมายเฉพาะในกรณีที่มันจะเป็นกฎหมายสำหรับการใด ๆ ที่Fooเป็นรอง
Ord

3
ว้าว. ยิ่งคุณเรียนรู้เกี่ยวกับข้อมูลทั่วไปของ Java มากเท่าไหร่คุณก็ยิ่งพบความเมายิ่งขึ้น
Mason Wheeler

คำตอบ:


15

ในขณะที่คุณได้ค้นพบด้วยตัวเองการArrayListประกาศให้เป็นArrayList<? extends Foo> subFoos = new ArrayList<>();จะไม่เป็นประโยชน์มาก

เพื่อดูประโยชน์ของการ<? extends T>พิจารณานี้:

List<Foo> collect( List<? extends Foo> a1, List<? extends Foo> a2 )
{
    List<Foo> collected = new ArrayList<>();
    collected.addAll( a1 );
    collected.addAll( a2 );
    return collected;
}

ซึ่งสามารถใช้ในภายหลังดังต่อไปนี้:

List<Foo> foos = collect( new ArrayList<Foo>(), new ArrayList<Bar>() );

หรือเป็นดังนี้:

List<Foo> foos = collect( new ArrayList<Bar>(), new ArrayList<Foo>() );

โปรดทราบว่าจะไม่มีการทำงานใด ๆ ข้างต้นหากcollectวิธีการดังกล่าวได้รับการประกาศดังนี้:

List<Foo> collect( List<Foo> a1, List<Foo> a2 )
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.