Genéricos: Lista es igual que Lista ?

Solo bash comprender la palabra clave extends en Java Generics.

List List significa que podemos rellenar cualquier objeto en la List que ES UN Animal

entonces, lo siguiente no significará lo mismo:

 List 

¿Alguien puede ayudarme a saber la diferencia entre los dos anteriores? Para mí se extends solo sonido redundante aquí.

¡Gracias!

List es un subtipo de List< ? extends Animal> List< ? extends Animal> , pero no un subtipo de List .

¿Por qué List no es un subtipo de List ? Considere el siguiente ejemplo:

 void mySub(List myList) { myList.add(new Cat()); } 

Si se le permitiera pasar una List a esta función, obtendría un error de tiempo de ejecución.


EDITAR: Ahora, si usamos List< ? extends Animal> List< ? extends Animal> lugar, sucederá lo siguiente:

 void mySub(List< ? extends Animal> myList) { myList.add(new Cat()); // compile error here Animal a = myList.get(0); // works fine } 

Podría pasar una List a esta función, pero el comstackdor se da cuenta de que agregar algo a la lista podría ocasionarle problemas. Si usa super lugar de extends (lo que le permite pasar una List ), es al revés.

 void mySub(List< ? super Animal> myList) { myList.add(new Cat()); // works fine Animal a = myList.get(0); // compile error here, since the list entry could be a Plant } 

La teoría detrás de esto es Co- y Contravariancia .

Veo que ya has aceptado una respuesta, pero me gustaría añadir mi opinión, ya que creo que puedo ser de ayuda aquí.

La diferencia entre List y List< ? extends Animal> List< ? extends Animal> es el siguiente.


Con List , sabes que lo que tienes es definitivamente una lista de animales. No es necesario que todos ellos sean exactamente ‘Animales’; también podrían ser tipos derivados. Por ejemplo, si tiene una Lista de animales, tiene sentido que una pareja pueda ser Cabra, y algunos de ellos Gatos, etc. ¿Verdad?

Por ejemplo, esto es totalmente válido:

 List aL= new List(); aL.add(new Goat()); aL.add(new Cat()); Animal a = aL.peek(); a.walk(); // assuming walk is a method within Animal 

Por supuesto, lo siguiente no sería válido:

 aL.peek().meow(); // we can't do this, as it's not guaranteed that aL.peek() will be a Cat 

Con List< ? extends Animal> List< ? extends Animal> , estás haciendo una statement sobre el tipo de lista con la que estás tratando.

Por ejemplo:

 List< ? extends Animal> L; 

Esto en realidad no es una statement del tipo de objeto que L puede contener . Es una statement sobre los tipos de listas a las que L puede hacer referencia.

Por ejemplo, podríamos hacer esto:

 L = aL; // remember aL is a List of Animals 

Pero ahora todo lo que el comstackdor sabe acerca de L es que es una Lista de [ya sea Animal o un subtipo de Animal] s

Entonces, lo siguiente no es válido:

 L.add(new Animal()); // throws a compiletime error 

Porque, por lo que sabemos, L podría estar haciendo referencia a una lista de Cabras, a la que no podemos agregar un Animal.

Este es el por qué:

 List gL = new List(); // fine gL.add(new Goat()); // fine gL.add(new Animal()); // compiletime error 

En lo anterior, estamos intentando lanzar un Animal como Cabra. Eso no funciona, porque ¿qué pasa si después de hacer eso tratamos de hacer que Animal haga un “cabezazo”, como lo haría una cabra? No necesariamente sabemos que el Animal puede hacer eso.

No lo es. List dice que el valor asignado a esta variable debe ser de “tipo” List . Sin embargo, esto no significa que solo debe haber objetos de Animal , también puede haber subclases.

 List l = new ArrayList(); l.add(4); // autoboxing to Integer l.add(6.7); // autoboxing to Double 

Usas la List< ? extends Number> List< ? extends Number> construir si le interesa una lista que tiene objetos Number , pero el objeto List no necesita ser del tipo List pero puede incluir cualquier otra lista de subclases (como List ).

En algún momento se usan los argumentos del método para decir “Quiero una lista de Numbers , pero no me importa si es solo List , también puede ser una List . Esto evita algunos lanzamientos extraños si tiene una lista de algunas subclases, pero el método espera una lista de la clase base.

 public void doSomethingWith(List l) { ... } List d = new ArrayList(); doSomethingWith(d); // not working 

Esto no funciona como esperaba List , no List . Pero si escribiste List< ? extends Number> List< ? extends Number> puede pasar los objetos de la List incluso si no son objetos de la List .

 public void doSomethingWith(List< ? extends Number> l) { ... } List d = new ArrayList(); doSomethingWith(d); // works 

Nota: Todo esto no está relacionado con la herencia de los objetos en la lista en sí. Todavía puede agregar objetos Double e Integer en una List , con o sin ? extends ? extends cosas