Parece que tengo un malentendido sobre la diferencia entre <Foo>
y <? extends Foo>
. Según tengo entendido, si tuviéramos
ArrayList<Foo> foos = new ArrayList<>();
Esto indica que Foo
se pueden agregar objetos de tipo a esta lista de matriz. Como las subclases de Foo
también son de tipo Foo
, también se pueden agregar sin error, como lo ilustra
ArrayList<Foo> foos = new ArrayList<>();
foos.add(new Foo());
foos.add(new Bar());
donde Bar extends Foo
.
Ahora, digamos que me había definido foos
como
ArrayList<? extends Foo> foos = new ArrayList<>();
Mi comprensión actual es que esto se expresa some unknown type that extends Foo
. Supongo que esto significa que cualquier objeto que sea una subclase de Foo
se puede agregar a esta lista; lo que significa que no hay diferencia entre ArrayList<Foo>
y ArrayList<? extends Foo>
.
Para probar esto, intenté escribir el siguiente código
ArrayList<? extends Foo> subFoos = new ArrayList<>();
subFoos.add(new Foo());
subFoos.add(new Bar());
pero se le solicitó el siguiente error de compilación
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)
Según mi comprensión actual, puedo ver por qué no podría agregar un Foo
a una lista de <? extends Foo>
, porque no es una subclase de sí mismo; pero tengo curiosidad por saber por qué no puedo agregar un Bar
a la lista.
¿Dónde está el agujero en mi entendimiento?
<? extends Foo>
es una clase específica y desconocida que se extiendeFoo
. Una operación con esta clase es legal solo si sería legal para cualquier subclase deFoo
.Respuestas:
Como has descubierto por ti mismo,
ArrayList
declarar comoArrayList<? extends Foo> subFoos = new ArrayList<>();
no sería muy útil.Para ver la utilidad de
<? extends T>
considerar esto:que luego se puede usar de la siguiente manera:
o como sigue:
tenga en cuenta que nada de lo anterior hubiera funcionado si el
collect
método se hubiera declarado de la siguiente manera:fuente