Lo sentimos, pero no se puede.
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). Esto significa que ninguna de estas son las asignaciones 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
Así que, dado esto, ¿qué tipo de objeto podría agregar a List foo3
que sería legal después de cualquiera de los anteriores posibles ArrayList
asignaciones:
- No puede agregar un
Integer
porque foo3
podría estar apuntando a 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 se puede agregar a cualquier objeto List<? extends T>
porque no se puede garantizar qué tipo de List
realmente está apuntando a, por lo que no se puede garantizar que el objeto esté previsto en ese 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
, p. Ej. 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 T específicas (por ejemplo Number
) de List<? super T>
porque no se puede garantizar qué tipo de List
realmente está apuntando. 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 <T> void copy(List<? super T> dest,List<? extends T> src)
Note como la declaración src
lista utiliza extends
que me permita pasar cualquier lista de una familia de tipos de lista correspondiente y aún garantiza que producirá valores de tipo T o subclases de T. Pero no puede agregar a la lista src
.
La declaración de lista dest
usa super
para permitirme pasar cualquier Lista de una familia de Tipos de Lista relacionados y aún así garantizar que puedo escribir un valor de un tipo específico T en esa lista. Pero no se puede garantizar que lea los valores de específicos tipo T si leo de la lista.
Así que ahora, gracias a los genéricos comodines, lo puede hacer cualquiera de estas llamadas con ese solo 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 amplia para ejercer su cerebro. Las líneas comentadas son ilegales y la razón está indicada en el extremo derecho de la línea (necesita 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>
Tenga en cuenta que 'List extiende el número> 'no significa 'lista de objetos de diferentes tipos, todos los cuales extienden' Número' ". Significa "lista de objetos de un _solo_ tipo que extiende' Número' ". –
Google 'Capture Conversion' para saber qué significa el error/advertencia. –
Será mejor que compruebe la regla de PECS, Producer extends, Consumer super. http://stackoverflow.com/questions/2723397/what-is-pecs-producer-extends-consumer-super – noego