wildcards type parameter method lower generic bound java generics bounded-wildcard

type - Java Generics(comodines)



java wildcard capture (7)

Tengo un par de preguntas sobre comodines genéricos en Java:

  1. ¿Cuál es la diferencia entre List<? extends T> List<? extends T> y List<? super T> List<? super T> ?

  2. ¿Qué es un comodín delimitado y qué es un comodín ilimitado?


En general,

Si una estructura contiene elementos con un tipo de la forma ? extends E ? extends E , podemos obtener elementos de la estructura, pero no podemos poner elementos en la estructura

List<Integer> ints = new ArrayList<Integer>(); ints.add(1); ints.add(2); List<? extends Number> nums = ints; nums.add(3.14); // compile-time error assert ints.toString().equals("[1, 2, 3.14]");

Para poner elementos en la estructura necesitamos otro tipo de comodín llamado Wildcards with super ,

List<Object> objs = Arrays.<Object>asList(2, 3.14, "four"); List<Integer> ints = Arrays.asList(5, 6); Collections.copy(objs, ints); assert objs.toString().equals("[5, 6, four]"); public static <T> void copy(List<? super T> dst, List<? extends T> src) { for (int i = 0; i < src.size(); i++) { dst.set(i, src.get(i)); } }


En tu primera pregunta, <? extends T> <? extends T> y <? super T> <? super T> son ejemplos de comodines delimitados. Un comodín ilimitado se parece a <?> , Y básicamente significa <? extends Object> <? extends Object> . Significa vagamente que el genérico puede ser de cualquier tipo. Un comodín delimitado ( <? extends T> o <? super T> ) coloca una restricción en el tipo diciendo que o bien tiene que extender un tipo específico ( <? extends T> se conoce como un límite superior), o tiene que ser un ancestro de un tipo específico ( <? super T> se conoce como un límite inferior).

Los Tutoriales de Java tienen algunas explicaciones bastante buenas de genéricos en los artículos Wildcards y Más Diversión con Comodines .


Josh Bloch también tiene una buena explicación de cuándo usar super y se extends en esta charla de video de google io, donde menciona que el Productor extends Consumer super mnemonic.

De las diapositivas de la presentación:

Supongamos que desea agregar métodos masivos a Stack<E>

void pushAll(Collection<? extends E> src);

- src es un productor de E

void popAll(Collection<? super E> dst);

- dst es un consumidor E


Los comodines genéricos se crean para que los métodos que operan en Colección sean más reutilizables.

Por ejemplo, si un método tiene un parámetro List<A> , solo podemos proporcionar List<A> a este método. Es un desperdicio para la función de este método en algunas circunstancias:

  1. Si este método solo lee objetos de List<A> , entonces debería permitírsele dar List<A-sub> a este método. (Debido a que A-sub IS a A)
  2. Si este método solo inserta objetos en la List<A> , entonces debería permitírsele asignar List<A-super> a este método. (Porque A ES un A-super)

Por ejemplo, tenemos la siguiente jerarquía de clases

Objeto <- A <- B, C

Deberías usar List <? extends A> List <? extends A> (límite superior) si vas a leer de la lista

Cuando sepa que las instancias en la colección son de instancias de A o subclases de A, es seguro leer las instancias de la colección y enviarlas a las instancias A.

No puede insertar elementos en la lista, porque no sabe si la lista está escrita en la clase A, B o C.

Deberías usar List <? super A> List <? super A> (límite inferior) si vas a insertar en la lista

Cuando sepa que la lista está escrita en A, o en una superclase de A, es seguro insertar instancias de A o subclases de A (por ejemplo, B o C) en la lista.

Sin embargo, no puede leer de la lista, excepto si arroja los objetos leídos a Object. Los elementos ya presentes en la lista podrían ser de cualquier tipo que sea una A o una superclase de A, pero no es posible saber exactamente qué clase es.

Lea más aquí - http://tutorials.jenkov.com/java-generics/wildcards.html


Puede haber ocasiones en las que desee restringir los tipos de tipos que pueden pasar a un parámetro de tipo. Por ejemplo, un método que opera con números solo podría querer aceptar instancias de Number o sus subclases. Esto es para lo que son los parámetros de tipo delimitados.

Collection<? extends MyObject>

significa que puede aceptar todos los objetos que tengan una relación IS-A con MyObject (es decir, cualquier objeto que sea un tipo de myObject o podemos decir cualquier objeto de cualquier subclase de MyObject) o un objeto de la clase MyObject.

Por ejemplo:

class MyObject {} class YourObject extends MyObject{} class OurObject extends MyObject{}

Entonces,

Collection<? extends MyObject> myObject;

aceptará solo MyObject o hijos de MyObject (es decir, cualquier objeto de tipo OurObject o YourObject o MyObject, pero no cualquier objeto de la superclase de MyObject).


Si tiene una jerarquía de clases A, B es una subclase de A, y C y D ambas son subclase de B como a continuación

class A {} class B extends A {} class C extends B {} class D extends B {}

Entonces

List<? extends A> la; la = new ArrayList<B>(); la = new ArrayList<C>(); la = new ArrayList<D>(); List<? super B> lb; lb = new ArrayList<A>(); //fine lb = new ArrayList<C>(); //will not compile public void someMethod(List<? extends B> lb) { B b = lb.get(0); // is fine lb.add(new C()); //will not compile as we do not know the type of the list, only that it is bounded above by B } public void otherMethod(List<? super B> lb) { B b = lb.get(0); // will not compile as we do not know whether the list is of type B, it may be a List<A> and only contain instances of A lb.add(new B()); // is fine, as we know that it will be a super type of A }

Un comodín delimitado es como ? extends B ? extends B donde B es de algún tipo. Es decir, el tipo es desconocido pero se puede colocar un "límite" sobre él. En este caso, está delimitado por alguna clase, que es una subclase de B.