Qual è la differenza tra <? estende Foo> e <Foo>


20

Mi sembra di avere un malinteso sulla differenza tra <Foo>e <? extends Foo>. Dalla mia comprensione, se avessimo

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

Ciò indica che è Foopossibile aggiungere oggetti di tipo a questo elenco di array. Poiché anche le sottoclassi di Foosono 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 fooscome

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

La mia attuale comprensione è che ciò esprime some unknown type that extends Foo. Presumo che ciò significhi che qualsiasi oggetto che è una sottoclasse di Foopuò essere aggiunto a questo elenco; significa che non c'è differenza tra ArrayList<Foo>eArrayList<? extends Foo> .

Per provare 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 della mia attuale comprensione, posso capire perché potrei non essere in grado di aggiungere un Fooa un elenco di <? extends Foo>, perché non è una sottoclasse di se stesso; ma sono curioso di sapere perché non riesco ad aggiungere aBar alla lista.

Dov'è il buco nella mia comprensione?



1
<? extends Foo>è una classe specifica e sconosciuta che si estende Foo. Un'operazione con questa classe è legale solo se sarebbe legale per qualsiasi sottoclasse di Foo.
Ordous,

3
Wow. Quanto più impari sui generici di Java, tanto maggiore è l'eccedenza.
Mason Wheeler,

Risposte:


15

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

Per vedere l'utilità di <? extends T>considerare 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 successivamente utilizzato 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>() );

si noti che nessuna delle precedenti avrebbe funzionato se il collectmetodo fosse stato dichiarato come segue:

List<Foo> collect( List<Foo> a1, List<Foo> a2 )
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.