2008-09-16 18 views
9
public static void main(String[] args) { 

    List<? extends Object> mylist = new ArrayList<Object>(); 

    mylist.add("Java"); // compile error 

} 

El código anterior no permite agregar elementos a la lista y las comodines solo se pueden usar como firma en los métodos, nuevamente no para agregar, sino solo para acceder. En este caso, ¿qué propósito cumple lo anterior?Colecciones de Java con el comodín

Respuesta

5

Digamos que usted tiene una interfaz y dos clases:

interface IResult {} 
class AResult implements IResult {} 
class BResult implements IResult {} 

entonces usted tiene clases que devuelven una lista como resultado:

interface ITest<T extends IResult> { 
    List<T> getResult(); 
} 

class ATest implements ITest<AResult> { 
    // look, overridden! 
    List<AResult> getResult(); 
} 

class BTest implements ITest<BResult> { 
    // overridden again! 
    List<BResult> getResult(); 
} 

Es una buena solución, cuando se necesita "covariante devuelve ", pero devuelve colecciones en lugar de sus propios objetos. La gran ventaja es que no tiene que lanzar objetos cuando usa ATest y BTest independientemente de la interfaz de ITest. Sin embargo, al usar la interfaz ITest, no puede agregar nada a la lista que se devolvió, ya que no puede determinar qué tipos de objetos contiene realmente la lista. Si estuviera permitido, podría agregar BResult a la lista <AResult> (devuelto como lista <? Extends T >), lo cual no tiene ningún sentido.

Así que debes recordar esto: Lista <? extends X > define una lista que se puede anular fácilmente, pero que es de solo lectura.

1

Con los genéricos de Java que usan comodines, se le permite la declaración anterior suponiendo que solo va a leer de ella.

No tiene permiso para agregar/escribir en él, porque todos los tipos genéricos deben ser eliminados en tiempo de compilación, y en tiempo de compilación no hay una forma en que el compilador sabe Lista son solo cadenas, (podría ser cualquier objeto que incluye cadenas!)

Sin embargo, está permitido leer, ya que al menos serán objetos. No se permiten mezclar diferentes tipos en las colecciones de Java para mantener las cosas limpias y comprensibles, y esto ayuda a garantizarlo.

+0

No, eso no está bien. Al menos desde el segundo párrafo de la explicación está fuera de tema. No se trata de borrado de tipo. – jrudolph

+0

El primer párrafo tampoco está bien. Puede eliminar o agregar null a una lista como se declaró en la pregunta, también puede agregar referencias (no nulas) si el comodín está definido con un supervínculo. –

1

El punto de los tipos de comodines acotados es su uso en las firmas de métodos para aumentar la flexibilidad de la API. Si, por ejemplo, se implementa un genérico Stack<E>, se podría proporcionar un método para impulsar una serie de elementos a la pila de este modo:

public void pushAll(Iterable<? extends E> elements) { 
    for(E element : elements){ 
     push(e); 
    } 
} 

En comparación con una firma pushAll(Iterable<E> elements) sin un comodín, esto tiene la ventaja de que permite que las colecciones de subtipos de E pasen al método; normalmente eso no se permitiría porque un Iterable<String> es, en contra de la intuición, una subclase de Iterable<Object>.

0

Esto funciona:

List<? super Object> mylist = new ArrayList<Object>(); 
mylist.add("Java"); // no compile error 

De Java Generics de O'Reilly:

El Obtener y Colocar Principio: utilizar un comodín se extiende cuando se consigue solamente los valores de nuestra estructura, utiliza un comodín súper cuando solo colocas valores en una estructura y no usas un comodín que obtienes y colocas.

+0

Creo que quisiste decir 'List '. –

+0

No. Copié el ejemplo de arriba y reemplacé 'extends' con 'super'. ¡Eso es! –

+1

PECS = producer extends, consumer super – helpermethod

0

List<? extends Object>, que es el mismo que List<?>, cumple con el propósito de generalizar todos los tipos List<String>, List<Number>, List<Object>, etc. (así que todos los tipos con un tipo adecuado en el lugar de la ?). Los valores de todos estos tipos se pueden asignar a una variable de tipo List<?> (que es donde difiere de List<Object>).

En general, no puede agregar una cadena a dicha lista. Sin embargo, puede leer Object de la lista y puede agregarle null. También puede calcular la longitud de la lista, etc. Estas son operaciones que se garantiza que funcionan para cada uno de estos tipos.

Para una buena introducción a los comodines, consulte el documento Adding Wildcards to the Java Programming Language. Es un documento académico, pero aún muy accesible.

0

Java Genéricos: comodines en las colecciones

  1. extiende
  2. súper
  3. ?

Hoy les voy a explicar cómo los comodines son útiles. Para entender este concepto es un poco difícil

Ahora supongamos que tiene una clase abstracta y en eso tiene un método abstracto llamado paintObject().

Now you want to use different type of collection in every child class. 

Este es el método de AbstractMain.

Aquí pasos que hemos tomado para este método abstracto principal

1. Hemos creado clase abstracta

2. En Parámetro tenemos definir T (se puede utilizar cualquier carácter) - En este caso, cualquiera que sea la clase que implemente este método, puede usar cualquier tipo de clase. ej. Clase puede implementar como método vacío paintObject (objeto ArrayList) pública o nula paintObject (objeto HashSet) pública

3. Y También hemos utilizado E se extiende MainColorTO - En este caso E se extiende MainColorTo - Es claramente significa cualquiera que sea la clase que desee usar que debe ser subclase de MainColorTo

4. Tenemos definir el método abstracto llamado paintObject (objeto T, E objectTO) --Ahora aquí lo que la clase es poner en práctica el método que el método se puede utilizar cualquier clase de primer argumento y el segundo parámetro que el método tiene que utilizar el tipo de MainColorTO

public abstract class AbstractMain<T,E extends MainColorTO> { 
     public abstract void paintObject(T Object,E TO); 
} 

Ahora vamos a extendernos por encima de la clase abstracta e implementar el método en la clase siguiente ej.

public class MainColorTO { 
    public void paintColor(){ 
      System.out.println("Paint Color........"); 
    } 
    } 

public class RedTO extends MainColorTO { 
    @Override 
    public void paintColor() { 
    System.out.println("RedTO......"); 
} 
} 
public class WhiteTO extends MainColorTO { 
    @Override 
    public void paintColor() { 
    System.out.println("White TO......"); 
    } 
} 

Ahora vamos a tomar dos ejemplos.

1.PaintHome.java

public class PaintHome extends AbstractMain<ArrayList, RedTO> { 
    @Override 
    public void paintObject(ArrayList arrayList,RedTO red) { 
     System.out.println(arrayList); 

    } 
} 

Ahora en PaintHome.java anterior se puede comprobar que hemos utilizado en ArrayList primer argumento (Como podemos tomar cualquier clase) y en el segundo argumento que ha usado RedTO (que es extendiendo MainColorTO)

2.PaintCar.java

public class PaintCar extends AbstractMain<HashSet, WhiteTO>{ 
    @Override 
    public void paintObject(HashSet Object,WhiteTO white) { 
     System.out.println(Object); 

    } 
} 

Ahora en PaintCar.java anterior se puede comprobar que hemos utilizado en HashSet primer argumento (como podemos tomar cualquier clase) y en el segundo argumento que hemos utilizado WhiteTO (¿Qué está extendiendo MainColorTO)

Ponint para recordar no puede utilizar palabra clave super a nivel de clase sólo se puede utilizar la palabra clave se extiende al nivel de clase defination

public abstract class AbstractMain<P,E super MainColorTO> { 

    public abstract void paintObject(P Object,E TO); 

} 

por encima de código le dará error del compilador.

Cuestiones relacionadas