Lo siento, pero no puedes.
La declaración comodín de 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 estos son tareas legales:
List<? extends Number> foo3 = new ArrayList<Number>; // Number "extends" Number
List<? extends Number> foo3 = new ArrayList<Integer>; // Integer extends Number
List<? extends Number> foo3 = new ArrayList<Double>; // Double extends Number
Entonces, dado esto, qué tipo de objeto podría agregar a List foo3
eso sería legal después de cualquiera de las posibles ArrayList
asignaciones anteriores :
- No puede agregar un
Integer
porque foo3
podría estar apuntando a un List<Double>
.
- No puede agregar un
Double
porque foo3
podría estar apuntando a un List<Integer>
.
- No puede agregar un
Number
porque foo3
podría estar apuntando a un List<Integer>
.
No puede agregar ningún objeto List<? extends T>
porque no puede garantizar a qué tipo de List
señal realmente está apuntando, por lo que no puede garantizar que el objeto esté permitido en eso 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>
. Estos son legales:
List<? super Number> foo3 = new ArrayList<Number>; // Number is a "super" of Number
List<? super Number> foo3 = new ArrayList<Object>; // Object is a "super" of Number
No puede leer el tipo específico T (p Number
. Ej. ) List<? super T>
Porque no 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 apunta.
El ejemplo perfecto de esto es la firma de Collections.copy()
:
public static <T> void copy(List<? super T> dest,List<? extends T> src)
Observe cómo la src
declaración de la lista usa extends
para permitirme pasar cualquier Lista de una familia de tipos de Lista relacionados y aún así garantizar que producirá valores de tipo T o subclases de T. Pero no puede agregar a la src
lista.
La dest
declaración de la lista super
me permite pasar cualquier Lista de una familia de tipos de Lista relacionados y aún así garantizar que pueda escribir un valor de un tipo T específico en esa lista. Pero no se puede garantizar la lectura de los valores de tipo específico T si leo de la lista.
Entonces, gracias a los comodines genéricos, puedo hacer cualquiera de estas llamadas con ese único método:
// copy(dest, src)
Collections.copy(new ArrayList<Number>(), new ArrayList<Number());
Collections.copy(new ArrayList<Number>(), new ArrayList<Integer());
Collections.copy(new ArrayList<Object>(), new ArrayList<Number>());
Collections.copy(new ArrayList<Object>(), new ArrayList<Double());
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 se indica en el extremo derecho de la línea (es necesario desplazarse para ver algunas de ellas):
List<Number> listNumber_ListNumber = new ArrayList<Number>();
//List<Number> listNumber_ListInteger = new ArrayList<Integer>(); // error - can assign only exactly <Number>
//List<Number> listNumber_ListDouble = new ArrayList<Double>(); // error - can assign only exactly <Number>
List<? extends Number> listExtendsNumber_ListNumber = new ArrayList<Number>();
List<? extends Number> listExtendsNumber_ListInteger = new ArrayList<Integer>();
List<? extends Number> listExtendsNumber_ListDouble = new ArrayList<Double>();
List<? super Number> listSuperNumber_ListNumber = new ArrayList<Number>();
//List<? super Number> listSuperNumber_ListInteger = new ArrayList<Integer>(); // error - Integer is not superclass of Number
//List<? super Number> listSuperNumber_ListDouble = new ArrayList<Double>(); // error - Double is not superclass of Number
//List<Integer> listInteger_ListNumber = new ArrayList<Number>(); // error - can assign only exactly <Integer>
List<Integer> listInteger_ListInteger = new ArrayList<Integer>();
//List<Integer> listInteger_ListDouble = new ArrayList<Double>(); // error - can assign only exactly <Integer>
//List<? extends Integer> listExtendsInteger_ListNumber = new ArrayList<Number>(); // error - Number is not a subclass of Integer
List<? extends Integer> listExtendsInteger_ListInteger = new ArrayList<Integer>();
//List<? extends Integer> listExtendsInteger_ListDouble = new ArrayList<Double>(); // error - Double is not a subclass of Integer
List<? super Integer> listSuperInteger_ListNumber = new ArrayList<Number>();
List<? super Integer> listSuperInteger_ListInteger = new ArrayList<Integer>();
//List<? super Integer> listSuperInteger_ListDouble = new ArrayList<Double>(); // error - Double is not a superclass of Integer
listNumber_ListNumber.add(3); // ok - allowed to add Integer to exactly List<Number>
// These next 3 are compile errors for the same reason:
// You don't know what kind of List<T> 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<Double>, even though it is really List<Number>
//listExtendsNumber_ListInteger.add(3); // error - can't add Integer to *possible* List<Double>, even though it is really List<Integer>
//listExtendsNumber_ListDouble.add(3); // error - can't add Integer to *possible* List<Double>, especially since it is really List<Double>
listSuperNumber_ListNumber.add(3); // ok - allowed to add Integer to List<Number> or List<Object>
listInteger_ListInteger.add(3); // ok - allowed to add Integer to exactly List<Integer> (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<X> that is only allowed to hold X's
listSuperInteger_ListNumber.add(3); // ok - allowed to add Integer to List<Integer>, List<Number>, or List<Object>
listSuperInteger_ListInteger.add(3); // ok - allowed to add Integer to List<Integer>, List<Number>, or List<Object>
List<? extends Number>
no significa "lista de objetos de diferentes tipos, todos los cuales se extiendenNumber
". Significa "lista de objetos de un solo tipo que se extiendeNumber
".