Qual è la differenza tra? estende Foo e Foo

14

Sembra che abbia un equivoco sulla differenza tra <Foo> e <? extends Foo> . Dalla mia comprensione, se avessimo

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

Questo indica che oggetti di tipo Foo possono essere aggiunti a questo elenco di array. Poiché le sottoclassi di Foo sono anche di tipo Foo , possono anche essere aggiunte senza errori, come illustrato da

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

dove Bar extends Foo .

Ora, dire che avevo definito foos come

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

La mia attuale comprensione è che questo esprime some unknown type that extends Foo . Prendo questo per significare che qualsiasi oggetto che sia una sottoclasse di Foo può essere aggiunto a questa lista; il che significa che non vi è alcuna differenza tra ArrayList<Foo> e ArrayList<? extends Foo> .

Per testare questo, ho provato a scrivere il seguente codice

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

ma è stato richiesto con il seguente errore di compilazione

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)

Sulla base delle mie attuali conoscenze, posso capire perché potrei non essere in grado di aggiungere un Foo a un elenco di <? extends Foo> , perché non è una sottoclasse di se stesso; ma sono curioso di sapere perché non riesco ad aggiungere un Bar alla lista.

Dove è il buco nella mia comprensione?

    
posta Zymus 25.11.2015 - 18:22
fonte

1 risposta

10

Come hai scoperto da solo, un ArrayList dichiarato come ArrayList<? extends Foo> subFoos = new ArrayList<>(); non sarebbe molto utile.

Per vedere l'utilità di <? extends T> , considera questo:

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

che può essere utilizzato in seguito come segue:

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

o come segue:

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

nota che nessuno dei precedenti avrebbe funzionato se il metodo collect fosse stato dichiarato come segue:

List<Foo> collect( List<Foo> a1, List<Foo> a2 )
    
risposta data 25.11.2015 - 19:55
fonte

Leggi altre domande sui tag