¿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 foo3 List 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 foo3 = new ArrayList; // Number "extends" Number List foo3 = new ArrayList; // Integer extends Number List 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 List 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 List . Estos son legales:

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

No puede leer el tipo específico T (por ejemplo, Number ) de List List 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 dest,List 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 listExtendsNumber_ListNumber = new ArrayList(); List listExtendsNumber_ListInteger = new ArrayList(); List listExtendsNumber_ListDouble = new ArrayList(); List listSuperNumber_ListNumber = new ArrayList(); //List listSuperNumber_ListInteger = new ArrayList(); // error - Integer is not superclass of Number //List 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 listExtendsInteger_ListNumber = new ArrayList(); // error - Number is not a subclass of Integer List listExtendsInteger_ListInteger = new ArrayList(); //List listExtendsInteger_ListDouble = new ArrayList(); // error - Double is not a subclass of Integer List listSuperInteger_ListNumber = new ArrayList(); List listSuperInteger_ListInteger = new ArrayList(); //List 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 //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 🙂