Como posso adicionar à lista estruturas de dados?

Eu tenho uma lista que é declarada assim:

List foo3 = new ArrayList(); 

Eu tentei adicionar 3 a foo3. No entanto, recebo uma mensagem de erro como esta:

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

Desculpe, mas você não pode.

A declaração curinga de List< ? extends Number> foo3 List< ? extends Number> foo3 significa que a variável foo3 pode conter qualquer valor de uma família de tipos (em vez de qualquer valor de um tipo específico). Isso significa que qualquer um deles é atribuições legais:

 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 

Então, dado isso, que tipo de object você poderia adicionar à List foo3 que seria legal após qualquer uma das atribuições ArrayList possíveis acima:

  • Você não pode adicionar um Integer porque foo3 pode estar apontando para uma List .
  • Você não pode adicionar um Double porque foo3 poderia estar apontando para um List .
  • Você não pode adicionar um Number porque foo3 poderia estar apontando para uma List .

Você não pode adicionar nenhum object à List< ? extends T> List< ? extends T> porque você não pode garantir que tipo de List está realmente apontando, então você não pode garantir que o object é permitido nessa List . A única “garantia” é que você só pode ler a partir dela e obterá um T ou uma subclass de T

A lógica inversa se aplica a super , por exemplo, List< ? super T> List< ? super T> . Estes são legais:

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

Você não pode ler o tipo específico T (por exemplo, Number ) da List< ? super T> List< ? super T> porque você não pode garantir que tipo de List está realmente apontando. A única “garantia” que você tem é que você pode adicionar um valor do tipo T (ou qualquer subclass de T ) sem violar a integridade da lista que está sendo apontada.


O exemplo perfeito disso é a assinatura de Collections.copy() :

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

Observe como a declaração de lista src extends para permitir que eu passe qualquer List de uma família de tipos de List relacionados e ainda garanta que ela produzirá valores do tipo T ou subclasss de T. Mas você não pode adicionar à lista src .

A declaração da lista de dest usa super para permitir que eu passe qualquer lista de uma família de tipos de lista relacionados e ainda garanto que posso escrever um valor de um tipo específico T para essa lista. Mas não é garantido que leia os valores do tipo específico T se eu ler na lista.

Então, agora, graças aos curingas genéricos, posso fazer qualquer uma dessas chamadas com esse ú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 e muito amplo para exercitar seu cérebro. As linhas comentadas são ilegais e a razão pela qual é indicada à extrema direita da linha (precisa rolar para ver algumas delas):

  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 

Você não pode (sem moldes inseguros). Você só pode ler a partir deles.

O problema é que você não sabe exatamente o que a lista é uma lista. Pode ser uma lista de qualquer subclass de Number, então quando você tenta colocar um elemento nela, você não sabe que o elemento realmente se encheckbox na lista.

Por exemplo, a lista pode ser uma lista de Byte , então seria um erro colocar um Float nela.

Você poderia fazer isso em vez disso:

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

“List ‘< '? Extends Number> é na verdade um caractere curinga de limite superior!

O caractere curinga com limite superior diz que qualquer class que estenda o número ou o próprio número pode ser usada como o tipo de parâmetro formal: O problema deriva do fato de que Java não sabe qual tipo realmente é a lista . Tem que ser um tipo EXACTO e ÚNICO. Espero que ajude 🙂