¿Cómo puedo agregar a List estructuras de datos?

Tengo una lista que se declara así:

List foo3 = new ArrayList(); 

Traté de agregar 3 a foo3. Sin embargo, recibo un mensaje de error como este:

 The method add(capture#1-of ? extends Number) in the type List is not applicable for the arguments (ExtendsNumber) 

Lo siento, pero no puedes.

La statement de comodín de List< ? extends Number> foo3 List< ? extends Number> foo3 significa que la variable foo3 puede contener cualquier valor de una familia de tipos (en lugar de cualquier valor de un tipo específico). Significa que cualquiera de estas son asignaciones legales:

 List< ? extends Number> foo3 = new ArrayList; // Number "extends" Number List< ? extends Number> foo3 = new ArrayList; // Integer extends Number List< ? extends Number> foo3 = new ArrayList; // Double extends Number 

Entonces, dado esto, ¿qué tipo de objeto podría agregar a la List foo3 que sería legal después de cualquiera de las posibles asignaciones de ArrayList anteriores?

  • No puede agregar un Integer porque foo3 podría estar apuntando a una List .
  • No puede agregar un Double porque foo3 podría estar apuntando a una List .
  • No puede agregar un Number porque foo3 podría estar apuntando a una List .

No puede agregar ningún objeto a la List< ? extends T> List< ? extends T> porque no puede garantizar a qué tipo de List apunta realmente, por lo que no puede garantizar que el objeto esté permitido en esa List . La única “garantía” es que solo puede leer de ella y obtendrá una T o subclase de T

La lógica inversa se aplica a super , por ejemplo, List< ? super T> List< ? super T> . Estos son legales:

 List< ? super Number> foo3 = new ArrayList; // Number is a "super" of Number List< ? super Number> foo3 = new ArrayList; // Object is a "super" of Number 

No puede leer el tipo específico T (por ejemplo, Number ) de List< ? super T> List< ? super T> porque no se puede garantizar a qué tipo de List apunta realmente. La única “garantía” que tiene es que puede agregar un valor de tipo T (o cualquier subclase de T ) sin violar la integridad de la lista a la que se está apuntando.


El ejemplo perfecto de esto es la firma de Collections.copy() :

 public static  void copy(List< ? super T> dest,List< ? extends T> src) 

Observe cómo se usa la statement de la lista src para permitirme pasar cualquier Lista de una familia de tipos de Lista relacionados y aún garantizar que producirá valores de tipo T o subclases de T. Pero no puede agregar a la lista src .

La statement de la lista dest usa super para permitirme pasar cualquier lista de una familia de tipos de listas relacionados y aún así garantizar que pueda escribir un valor de un tipo específico T en esa lista. Pero no se puede garantizar que lea los valores del tipo específico T si leo de la lista.

Así que ahora, gracias a los comodines generics, puedo hacer cualquiera de estas llamadas con ese único método:

 // copy(dest, src) Collections.copy(new ArrayList(), new ArrayList(), new ArrayList(), new ArrayList()); Collections.copy(new ArrayList(), new ArrayList 

Considere este código confuso y muy amplio para ejercitar su cerebro. Las líneas comentadas son ilegales y la razón por la cual está indicada en el extremo derecho de la línea (necesita desplazarse para ver algunas de ellas):

  List listNumber_ListNumber = new ArrayList(); //List listNumber_ListInteger = new ArrayList(); // error - can assign only exactly  //List listNumber_ListDouble = new ArrayList(); // error - can assign only exactly  List< ? extends Number> listExtendsNumber_ListNumber = new ArrayList(); List< ? extends Number> listExtendsNumber_ListInteger = new ArrayList(); List< ? extends Number> listExtendsNumber_ListDouble = new ArrayList(); List< ? super Number> listSuperNumber_ListNumber = new ArrayList(); //List< ? super Number> listSuperNumber_ListInteger = new ArrayList(); // error - Integer is not superclass of Number //List< ? super Number> listSuperNumber_ListDouble = new ArrayList(); // error - Double is not superclass of Number //List listInteger_ListNumber = new ArrayList(); // error - can assign only exactly  List listInteger_ListInteger = new ArrayList(); //List listInteger_ListDouble = new ArrayList(); // error - can assign only exactly  //List< ? extends Integer> listExtendsInteger_ListNumber = new ArrayList(); // error - Number is not a subclass of Integer List< ? extends Integer> listExtendsInteger_ListInteger = new ArrayList(); //List< ? extends Integer> listExtendsInteger_ListDouble = new ArrayList(); // error - Double is not a subclass of Integer List< ? super Integer> listSuperInteger_ListNumber = new ArrayList(); List< ? super Integer> listSuperInteger_ListInteger = new ArrayList(); //List< ? super Integer> listSuperInteger_ListDouble = new ArrayList(); // error - Double is not a superclass of Integer listNumber_ListNumber.add(3); // ok - allowed to add Integer to exactly List // These next 3 are compile errors for the same reason: // You don't know what kind of List is really // being referenced - it may not be able to hold an Integer. // You can't add anything (not Object, Number, Integer, // nor Double) to List< ? extends Number> //listExtendsNumber_ListNumber.add(3); // error - can't add Integer to *possible* List, even though it is really List //listExtendsNumber_ListInteger.add(3); // error - can't add Integer to *possible* List, even though it is really List //listExtendsNumber_ListDouble.add(3); // error - can't add Integer to *possible* List, especially since it is really List listSuperNumber_ListNumber.add(3); // ok - allowed to add Integer to List or List listInteger_ListInteger.add(3); // ok - allowed to add Integer to exactly List (duh) // This fails for same reason above - you can't // guarantee what kind of List the var is really // pointing to //listExtendsInteger_ListInteger.add(3); // error - can't add Integer to *possible* List that is only allowed to hold X's listSuperInteger_ListNumber.add(3); // ok - allowed to add Integer to List, List, or List listSuperInteger_ListInteger.add(3); // ok - allowed to add Integer to List, List, or List 

No puedes (sin moldes inseguros). Solo puedes leer de ellos.

El problema es que no sabes de qué exactamente es una lista. Podría ser una lista de cualquier subclase de Número, de modo que cuando tratas de ponerle un elemento, no sabes que el elemento realmente cabe en la lista.

Por ejemplo, la Lista podría ser una lista de Byte , por lo que sería un error colocar un Float en ella.

Usted podría hacer esto en su lugar:

  List foo3 = new ArrayList(); foo3.add(3); 

“List ‘< '? Extends Number> es en realidad un comodín de límite superior.

El comodín de límite superior dice que cualquier clase que amplíe Number o Number se puede usar como el tipo de parámetro formal: el problema surge del hecho de que Java no sabe qué tipo es realmente List . Tiene que ser un tipo EXACTO y ÚNICO. Espero que ayude 🙂