¿Cuál es la diferencia entre? extiende Foo y Foo

14

Parece que tengo un malentendido sobre la diferencia entre <Foo> y <? extends Foo> . A mi entender, si tuviéramos

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

Esto indica que se pueden agregar objetos de tipo Foo a esta lista de matriz. Como las subclases de Foo también son del tipo Foo , también pueden agregarse sin errores, como se ilustra en

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

donde Bar extends Foo .

Ahora, digamos que había definido foos como

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

Mi entendimiento actual es que esto expresa some unknown type that extends Foo . Entiendo 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 preguntó con 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 puedo agregar Foo a una lista de <? extends Foo> , porque no es una subclase de sí misma; pero tengo curiosidad por saber por qué no puedo agregar un Bar a la lista.

¿Dónde está el agujero en mi entendimiento?

    
pregunta Zymus 25.11.2015 - 18:22

1 respuesta

10

Como usted mismo descubrió, un ArrayList declarado como ArrayList<? extends Foo> subFoos = new ArrayList<>(); no sería muy útil.

Para ver la utilidad de <? extends T> considera esto:

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

que puede utilizarse más adelante de la siguiente manera:

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

o como sigue:

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

tenga en cuenta que ninguno de los anteriores habría funcionado si el método collect se hubiera declarado de la siguiente manera:

List<Foo> collect( List<Foo> a1, List<Foo> a2 )
    
respondido por el Mike Nakis 25.11.2015 - 19:55

Lea otras preguntas en las etiquetas