2012-03-06 20 views
12

Ésta es parte de la interfaz (1.6) Colección de Java:colección genérica

public interface Collection<E> extends java.lang.Iterable<E> { 
    /* ... */ 
    boolean containsAll(java.util.Collection<?> objects);  
    boolean addAll(java.util.Collection<? extends E> es);  
    boolean removeAll(java.util.Collection<?> objects);  
    boolean retainAll(java.util.Collection<?> objects); 
    /* ... */ 
} 

¿Por qué tener addAll<? extends E> mientras removeAll tiene <?>

Respuesta

12

No sabía, busqué en Google.Tengo esta explicación aquí: http://www.ibm.com/developerworks/java/library/j-jtp01255/index.html

Copia de la parte:

Un elemento de la API Colecciones generifed que a menudo es confuso al principio es la firma de containsAll(), removeAll(), y retainAll() . Se podría esperar que las firmas de Remove() y removeAll() para ser:

interface Collection<E> { 
    public boolean remove(E e); // not really 
    public void removeAll(Collection<? extends E> c); // not really 
} 

Pero en realidad es:

interface Collection<E> { 
    public boolean remove(Object o); 
    public void removeAll(Collection<?> c); 
} 

¿Por qué es esto? De nuevo, la respuesta radica en la compatibilidad con versiones anteriores. El contrato de interfaz de x.remove (o) significa "si o está contenido en x, elimínelo; de lo contrario, no haga nada". Si x es una colección genérica, o no tiene que ser compatible con el tipo de parámetro de tipo x. Si removeAll() se generified sólo para ser exigible si su argumento era de tipo-compatible (Collection<? extends E>), a continuación, ciertas secuencias de código que eran legales antes de los genéricos se convertiría en ilegal, como éste:

// a collection of Integers 
Collection c = new HashSet(); 
// a collection of Objects 
Collection r = new HashSet(); 
c.removeAll(r); 

Si el fragmento anterior se generaron de la manera obvia (haciendo ca Collection<Integer> y ra Collection<Object>), entonces el código anterior no se compilaría si la firma de removeAll() requiriera que su argumento fuera un Collection<? extends E>, en lugar de ser un no-op. Uno de los objetivos clave de la generación de las bibliotecas de clase era no romper o cambiar la semántica del código existente, por lo que remove(), removeAll(), retainAll() y containsAll() tenían que definirse con una restricción de tipo más débil que podría haber sido rediseñado desde cero para los genéricos.

0

Java implementa genéricos a través de borrado. Esta información es solo para tiempo de compilación. Supongo que los diseñadores de la colección java hicieron esto para retener una mayor compatibilidad ascendente con la versión java pre-genérica.

+2

Eso no es lo que está preguntando. – SLaks

+0

Lo siento si no entendí bien. :( – Nicocube

0

cuando agrega un objeto, debe ser una subclase (o sub-subclase, etc.) del tipo principal. Cuando elimina un objeto, lo devuelve como el tipo de la colección. Este es un buen ejemplo de polymorphism en acción.

0

¿A quién le importa lo que intenta eliminar?

Agregar es otra cosa; no nos gustaría terminar con algo extraño en nuestra colección.

según lo solicitado; un ejemplo:

import java.util.ArrayList; 
import java.util.Collection; 
import java.util.List; 

public class Main { 

    private static class A { 

    } 

    public static void main(String[] args) { 
     Collection<A> collection_A = new ArrayList<A>(); 

     Collection<String> collection = new ArrayList<String>(); 

     // no problem to try and remove things that wouldn't be there in the first place; either way, they are gone afterwards 
     collection.removeAll(collection_A); 

     // we can't allow this; you would end up with things in your collection that don't belong there 
     collection.addAll(collection_A); 
    } 

} 
+0

¿Podría ilustrar esto con un ejemplo específico o dos? – NPE

2

Cuando agrega un elemento a su colección, quiere asegurarse de que tenga un cierto tipo.

Cuando los elimina, solo se eliminan los de la colección. Independientemente de su tipo.

3

<?> es menos restrictivo que <? extends E>.

No hay nada de malo en quitar una naranja de una colección de manzanas; hay muchas cosas mal con agregando una naranja a una colección de manzanas.

+0

Sé lo que quiere decir ... había jugo de orage en todas partes. Esos dos nunca se llevan bien. +1 –

+0

Sí, pero dado que no hay forma de * agregar * un naranja a una colección de manzanas, la colección no puede contener una naranja, por lo que 'removeAll()' también podría tomar '', ¿no? – NPE

+2

@aix: Esto le permite pasar una colección de 'Fruta' (o incluso 'Object') y eliminar todas sus manzanas de su colección. – SLaks

7

Para cualquier colección que contenga elementos del tipo E, addAll debe ser capaz de tratar con colecciones de entrada no solo de E, sino también de todas sus subclases. Por lo tanto, <? extends E>. Sin esto, no podría agregar todos los elementos de List<Integer> a List<Number>, lo que claramente no sería correcto. *

Para su eliminación, no es necesario establecer estrictamente los límites, y no hay daño al intentar eliminar elementos de una colección de algún tipo totalmente no relacionado. P.ej. puede tener una colección de Number s, de la cual sabe que solo contiene Integer s, por lo que pasarla a removeAll en un List<Integer> debería funcionar bien, y sería estúpido que el compilador no lo permitiera.

Tenga en cuenta que according to the Javadoc, removeAll opcionalmente puede arrojar un ClassCastException, dependiendo de la implementación.

* La razón detrás de esto es que en Java, los genéricos son invariantes. Para obtener más detalles, consulte, por ejemplo, this thread.

0

Un ejemplo sencillo para ilustrar lo dicho:

public class Test { 

    public static void main(String[] args) { 
     List<String> l = new ArrayList<String>(); 
     System.out.println(l.remove(new Object())); //false 
     System.out.println(l.contains(new Object())); //false 
//  l.add(new Object()); // does not compile 
    } 

} 
0

eliminar no es necesaria la restricción, por lo que sólo <?>, pero al tiempo que añade tenemos que comprobar y luego añadir a la seguridad de tipos, por lo addAll está con la restricción <? extends E>

0

Con addAll desea poder agregar todos los elementos que son un subtipo del tipo genérico. Esto incluye agregar todos los elementos de List<String> a List<Object>. Usamos ? extends E para aceptar cualquier colección que contenga el tipo almacenado en esta colección o cualquier subtipo.

boolean addAll(java.util.Collection<? extends E> es); 
List<Number> numbers = ...; 
List<Integer> integers = ...; 
numbers.addAll(integers);//works  

boolean addAll(java.util.Collection<E> es); 
numbers.addAll(integers);//does not work E != Integer 

no podemos usar como ? que elimine cualquier seguridad proporcionada por los genéricos.

boolean addAll(java.util.Collection<? extends E> es); 
List<Number> numbers = ...; 
List<Integer> integers = ...; 
List<String> strings = ...; 
numbers.addAll(integers);//works 
numbers.addAll(strings);//error 

boolean addAll(java.util.Collection<?> es); 
numbers.addAll(strings);//works - now we have strings in our Number collection 

Podemos utilizar ? para eliminar los objetos ya tratar de eliminar una cadena de Lista de números suele afectar a un List<Number>.

boolean removeAll(java.util.Collection<?> objects); 
List<Objects> objects = ...; 
List<Integer> integers = ...; 
List<Number> numbers = ...; 
numbers.removeAll(objects);//works 
numbers.removeAll(integers);//works 

boolean removeAll(java.util.Collection<? extends E> objects); 
numbers.removeAll(objects);//does not work 
numbers.removeAll(integers);//works 

boolean removeAll(java.util.Collection<? super E> objects); 
numbers.removeAll(objects);//works 
numbers.removeAll(integers);//does not work 
Cuestiones relacionadas