type parameter method generic example java generics generic-list generic-collections

java - parameter - Las listas con comodines causan un error de vudú genérico



java generics wildcard example (5)

(Supongo que Bar y Baz son ambos subtipos de Foo ).

List<? extends Foo> List<? extends Foo> significa una lista de elementos de algún tipo, que es un subtipo de Foo, pero no sabemos qué tipo . Ejemplos de tales listas serían una ArrayList<Foo> , una LinkedList<Bar> y una ArrayList<Baz> .

Como no sabemos qué subtipo es el parámetro tipo, no podemos poner objetos Foo en él, ni objetos Bar o Baz . Pero todavía sabemos que el parámetro de tipo es un subtipo de Foo , por lo que cada elemento que ya está en la lista (y que podemos obtener de la lista) debe ser un objeto Foo , por lo que podemos usar Foo f = list.get(0); y cosas similares.

Dicha lista solo puede usarse para sacar elementos de la lista, no para agregar elementos (aparte de null , pero no sé si el compilador realmente lo permite).

Una List<Foo> por otro lado, permite agregar cualquier objeto que sea Foo , y como Bar y Baz son subtipos de Foo , todos los objetos Bar y Baz son objetos Foo , por lo que se pueden agregar también.

¿Alguien sabe por qué el siguiente código no compila? Ni add () ni addAll () funcionan como se esperaba. Eliminar la parte "? Extends" hace que todo funcione, pero no podría agregar subclases de Foo.

List<? extends Foo> list1 = new ArrayList<Foo>(); List<? extends Foo> list2 = new ArrayList<Foo>(); /* Won''t compile */ list2.add( new Foo() ); //error 1 list1.addAll(list2); //error 2

error 1:

IntelliJ dice:

add(capture<? extends Foo>) in List cannot be applied to add(Foo)

El compilador dice:

cannot find symbol symbol : method addAll(java.util.List<capture#692 of ? extends Foo>) location: interface java.util.List<capture#128 of ? extends Foo>

error 2:

IntelliJ me da

addAll(java.util.Collection<? extends capture<? extends Foo>>) in List cannot be applied to addAll(java.util.List<capture<? extends Foo>>)

Mientras que el compilador simplemente dice

cannot find symbol symbol : method addAll(java.util.List<capture#692 of ? extends Foo>) location: interface java.util.List<capture#128 of ? extends Foo> list1.addAll(list2);


Déjame intentar explicar en qué caso podrías necesitar usar <? extend Classname> <? extend Classname> .

Entonces, digamos que tienes 2 clases:

class Grand { private String name; public Grand(String name) { this.setName(name); } public Grand() { } public void setName(String name) { this.name = name; } } class Dad extends Grand { public Dad(String name) { this.setName(name); } public Dad() { } }

Y digamos que tienes 2 colecciones, cada una contiene algunos Grands y algunos Dads:

List<Dad> dads = new ArrayList<>(); dads.add(new Dad("Dad 1")); dads.add(new Dad("Dad 2")); dads.add(new Dad("Dad 3")); List<Dad> grands = new ArrayList<>(); dads.add(new Dad("Grandpa 1")); dads.add(new Dad("Grandpa 2")); dads.add(new Dad("Grandpa 3"));

Ahora, supongamos que queremos tener una colección, que contendrá objetos Grand o Dad:

List<Grand> resultList; resultList = dads; // Error - Incompatable types List<Grand> List<Dad> resultList = grands;//Works fine

¿Cómo podemos evitar esto? Simplemente use comodín:

List<? extends Grand> resultList; resultList = dads; // Works fine resultList = grands;//Works fine

Tenga en cuenta que no puede agregar nuevos elementos en dicha colección (resultList). Para obtener más información, puede leer sobre Wildcard y la consecución de PECS en Java


Lo siento, tal vez entendí mal su pregunta, pero supongo que:

public class Bar extends Foo{ }

este código:

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

no generes ningún error para mí

Por lo tanto, eliminar el comodín permite agregar subclases de Foo.


Recuerde PECS: Producer Extends, Consumer Super .

Como intenta agregar elementos a list2, es un consumidor y no puede declararse como List<? extends Foo> List<? extends Foo> . Pero también está usando list2 como productor cuando lo agrega a list1. Por lo tanto, list2 es tanto un productor como un consumidor y debe ser una List<Foo> .

list1, como consumidor puro, puede ser una List<? super Foo> List<? super Foo> .


Son errores. Modifiquemos su código, considerando que Bar y Baz son dos tipos diferentes que se extienden Foo :

List<? extends Foo> list1 = new ArrayList<Bar>(); List<? extends Foo> list2 = new ArrayList<Baz>();

Si list1.add(new Foo()) estaba permitido, podría agregar instancias de Foo en una colección que contenga instancias de Bar. Esto explica el primer error.

Si se list1.addAll(list2) , todas las instancias de Baz en list2 se agregarían a list1, que contiene solo instancias de Bar. Esto explica el segundo error.