List<? extends Base> list
List<Base> list
¿Hay alguna diferencia entre las dos declaraciones?Lista <? extiende Base> VS List <Base>
Gracias,
List<? extends Base> list
List<Base> list
¿Hay alguna diferencia entre las dos declaraciones?Lista <? extiende Base> VS List <Base>
Gracias,
Sí.
List<Base>
puede contener una mezcla de diferentes cosas que todos derivan de Base
. List<? extend Base>
contiene elementos homogéneos (en el sentido de que todos deben derivar de algún tipo específico desconocido que a su vez deriva de Base
).
Dicho de otra manera, List<? extends Base>
es la clase base para List<T extends Base>
. Entonces puede pasar un List<T extends Base>
a cualquier método que tome un List<? extends Base>
. Lo mismo no es cierto para los métodos que toman un List<Base>
.
List<Base> list
puede contener elementos de tipo Base
o cualquiera de sus subtipos. Algunos ejemplos de las clases de JDK:
List<Object> objects = new ArrayList<Object>();
objects.add(new Object()); // adding an Object instance
objects.add("I am a String"); // a String instance is also an Object
objects.add(Integer.valueOf(5)); // an Integer instance is also an Object
Pero cuando se recuperan los elementos, puede asignar únicamente a las variables de la clase Object
, porque Object
es el parámetro de tipo de la lista declarado.
Object first = objects.get(1);
Object second = objects.get(2);
Object third = objects.get(3);
Sus clases reales de ejecución son todavía Object
, String
y Integer
, por lo que pueden echarlos a esos tipos y trabajar con ellos como tal, pero este tipo de moldes pueden fallar en tiempo de ejecución con un ClassCastException
si no se hace bien y es En general, no es una buena idea trabajar con listas de esa manera.
List<? extends Base> list
es una declaración de que no es en realidad designado para la declaración de variables, porque como ya se ha mencionado en el comentario de Daniel Pryden - Puede no add()
cualquier objeto en ella, sólo null
s.
List<? extends String> list = new ArrayList<? extends String>();
list.add("a String")); // compile error!
Pero se puede utilizar una expresión tan acotada comodín para los parámetros de los métodos genéricos. Un ejemplo de la List
sí es el método addAll()
cuya firma es la siguiente:
boolean addAll(Collection<? extends E> c);
Esto le permite hacer algo como esto:
List<String> strings = Arrays.asList("a", "b");
List<Object> objects = new ArrayList<Object>();
objects.addAll(strings);
Sin la <? extend E>
comodín que no sería posible añadir aquellos String
s en List
de Object
s, porque los tipos genéricos (a diferencia de las matrices) no son covariantes. Eso significa que un List<String>
no es un subtipo de List<Object>
. Pero cualquier String
es un Object
, ¿verdad? Por lo tanto, es necesario declarar el parámetro del método con el comodín delimitado; un List<String>
es, un subtipo de List<? extends Object>
.
Una vez más, tengo que señalar que el comodín delimitado está designado principalmente para los parámetros de método genérico , no para los tipos de retorno de método o las declaraciones de variables.
En particular, no puede agregar un objeto de tipo 'Base' a una' Lista extiende Base> '. –
@LouisWasserman: No solo eso, pero no puede agregar * any * objeto (excepto 'null') a' List extiende Base> ', porque no sabes qué tipo representa el'? '. –
@LouisWasserman: ¿En resumen, List extiende Base> se puede pasar a cualquier método que tome cualquiera de List extiende Base>, Lista , Lista , o Lista ? Entonces, ¿por qué alguien querría usar List ? Lo que también me desconcierta es que puedes hacer .add (...) en ambos List extiende Base> y Lista , donde '...' puede ser cualquier cosa que sea Base o derivada (directa o indirectamente) de Base. –
user113454