2008-10-30 12 views
89

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

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

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

+0

En el caso de que [Ted Gao] (http://stackoverflow.com/users/970122/ted-gao) [respuesta] (http://stackoverflow.com/a/9446233/2476755) se elimina (ya que era solo un enlace), aquí está la [publicación de blog] (http://ted-gao.blogspot.com/search/label/Java%20Generics) a la que enlaza . – royhowie

Respuesta

104

En su primera pregunta, <? extends T> y <? super T> son ejemplos de comodines acotadas. Un comodín ilimitado se ve como <?>, y básicamente significa <? extends Object>. Significa vagamente que el genérico puede ser de cualquier tipo. Un comodín acotada (<? extends T> o <? super T>) impone 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 antepasado de un tipo específico (<? super T> es conocido como un límite inferior).

Los tutoriales de Java tienen algunas explicaciones bastante buenas de los genéricos en los artículos Wildcards y More Fun with Wildcards.

+0

Solo para hacerlo bien, si A es incorrecto? –

+0

Si por A para limitar sus elecciones a A o B. –

+0

y en ese caso si digo ¿cuál sería la diferencia? –

42

Si tiene una jerarquía de clases A, B es una subclase de A, y C y D ambos 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 acotada es como ? extends B donde B es un tipo. Es decir, el tipo es desconocido pero se puede colocar un "límite" sobre él. En este caso, es limitado por alguna clase, que es una subclase de B.

+1

+1 por ejemplos. –

+1

gran ejemplo, gracias – Peter

36

Josh Bloch también tiene una buena explicación de cuándo utilizar super y extends en este google io video talk donde menciona los Productor extends de consumo super mnemotécnica .

De las diapositivas de la presentación:

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

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

- src es un productor E

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

- DST es un consumidor E

+0

He leído el libro de Bloch, pero todavía no puedo ver la diferencia entre extends y super en este caso particular. –

+0

Mira el video, creo que está bastante claro. Además, creo que deberías hacer otra pregunta sobre este "cuál es la diferencia entre List y List " donde es de esperar que obtengas más respuestas. (si lo hace, agregue un enlace desde aquí) – blank

+2

Camas: por qué no incluir el ejemplo en esta respuesta para que sea completo y independiente. Los enlaces son efímeros. –

2

Es posible que en ocasiones 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 tienen es, un relación con MiObjeto (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; 

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

1

En general,

Si una estructura contiene elementos con un tipo de forma ? extends E, podemos obtener los 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 que necesitamos otro tipo de comodines llamada 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)); 
     } 
    } 
0

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 una pérdida para la funcion de este método en algunas circunstancias:

  1. Si este método sólo lee los objetos de List<A>, a continuación, se nos debería permitir dar List<A-sub> a este método. (Debido a que A-sub IS a)
  2. Si este método solo inserta objetos en List<A>, entonces se nos debe permitir dar List<A-super> a este método. (Debido a que A es un A-súper)
0

Por ejemplo tenemos el siguiente jerarquía de clases

objeto < - Un < - B, C

Debe utilizar List <? extends A> (superior obligado) si va a lea de la lista

Cuando sabe que las instancias en la colección son de instancias de A o de subclases de A, es seguro para leer las instancias de la colección y convertirlas en instancias A.

Usted no puede insertar elementos en la lista, porque no sabe si la lista se escribe a la clase A, B o C.

Debe utilizar List <? super A> (límite inferior) si se va a inserción en la lista

Cuando se sabe que la lista se escribe a los puntos A, o una superclase de A, es seguro para insertar instancias de A o subclases de A (por ejemplo, B o C) en la lista.

Usted no puede leer de la lista, excepto si arroja los objetos leídos a Objeto. 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.

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