2010-03-10 32 views
24

Veo que Collections.unmodifiableSet devuelve una vista no modificable del conjunto dado pero no entiendo por qué no podemos simplemente usar el modificador final para lograr esto.¿Qué hace Collections.unmodifiableSet() en Java?

En mi comprensión, final declara una constante: algo que no se puede modificar. Por lo tanto, si un conjunto se declara como una constante, no se puede modificar: no se puede eliminar nada del conjunto y no se puede agregar nada.

¿Por qué necesitamos Collections.unmodifiableSet?

Respuesta

51

final declara una referencia de objeto que no se puede modificar, p.

private final Foo something = new Foo(); 

crea un nuevo Foo y coloca la referencia en something.A partir de entonces, no es posible alterar something para apuntar a una instancia diferente de Foo.

Esto no no impide la modificación del estado interno del objeto. Todavía puedo llamar a cualquier método en Foo que esté accesible para el alcance correspondiente. Si uno o más de esos métodos modifica el estado interno de ese objeto, entonces final no evitará eso.

Como tal, los siguientes:

private final Set<String> fixed = new HashSet<String>(); 

hace no crear un Set que no puede ser añadido a o de otra manera alterado; solo significa que fixed solo hará referencia a esa instancia.

Por el contrario, haciendo:

private Set<String> fixed = Collections.unmodifiableSet(new HashSet<String>()); 

crea una instancia de un Set que tirar UnsupportedOperationException si se intenta llamar fixed.add() o fixed.remove(), por ejemplo - el objeto en sí protegerá su estado interno y evitar que se siendo modificado.

Para completarlo:

private final Set<String> fixed = Collections.unmodifiableSet(new HashSet<String>()); 

crea una instancia de un Set que no permitirá que su estado interno a ser cambiado, y también significa que fixed sólo se deberá apuntar a una instancia de ese conjunto.

El motivo por el que final se puede usar para crear constantes de primitivas se basa en el hecho de que el valor no se puede cambiar. Recuerde que fixed arriba era solo una referencia, una variable que contiene una dirección que no se puede cambiar. Bueno, para primitivos, p.

private final int ANSWER = 42; 

el valor de ANSWER es que 42. Desde ANSWER no puede ser cambiado, solamente siempre tendrá el valor 42.

Un ejemplo que borra todas las líneas sería la siguiente:

private final String QUESTION = "The ultimate question"; 

Según las reglas anteriores, QUESTION contiene la dirección de una instancia de String que representa "La última pregunta", y esa dirección no se puede cambiar. Lo que hay que recordar aquí es que el String es inmutable: no se puede hacer nada con una instancia de String que lo cambie, y cualquier operación que lo haga (como replace, substring, etc.) devolverá referencias completamente diferentes instancias de String.

14

final sólo garantiza que la referencia al objeto representa la variable no se puede cambiar que no hace nada por la instancia del objeto y su mutabilidad.

final Set s = new Set(); simplemente garantiza que no se puede hacer s = new Set(); nuevamente. No hace que el conjunto no se pueda modificar, si no pudieras agregarle nada, para empezar. Para que quede muy claro, final solo afecta a la variable referencia, no es el objeto al que hace referencia la referencia.

que puede hacer lo siguiente:

final List<String> l = new ArrayList<String>(); 
l.add("hello"); 
l.add("world"); 
l.remove(0); 

pero no puedo hacer esto.

l = new ArrayList<String>(); 

nuevo debido a la final no puedo modificar lo que los puntos l variables a.

tiene que hacer una de las tres cosas siguientes para hacer que un hilo del contenedor de colección sea seguro.

java.util.Collections.syncronizedXXX(); 

o

java.util.Collections.unmodifiableXXX(); 

o uso uno de los contenedores adecuados de java.util.concurrency.* package.

Si tuviera un objeto Person e hicieron final Person p = new Person("me"); que significa que no puedo reasignar p para apuntar a otro objeto Person. Todavía puedo hacer p.setFirstName("you");

Lo que confunde la situación es que

final int PI = 3.14; 
final String greeting = "Hello World!"; 

mirada como const en C++, cuando en realidad los objetos a los que apunten son inmutables/inmodificable por naturaleza. Los contenedores u objetos con métodos de mutador que pueden alterar el estado interno del objeto no son const solo referencia para esos objetos son final y no se pueden reasignar a referencia otro objeto.

+1

Good post. En resumen, la _reference_ no se puede cambiar, pero el _contents_ del objeto * puede *. – extraneon

3

final no es (C++ - estilo) const. A diferencia de C++, Java no tiene const -metodos ni nada de eso, y los métodos que pueden cambiar el objeto se pueden llamar a través de una referencia final.

Collections.unmodifiable* es un contenedor que impone (en tiempo de ejecución solamente, no en tiempo de compilación) la capacidad de solo lectura para la colección en cuestión.

0

El Collections.unmodifiableSet(Set<? extends T>) creará un contenedor en el conjunto original. Este conjunto de envoltura no se puede modificar. pero aún así el conjunto original puede ser modificado.

Ejemplo:

Set<String> actualSet=new HashSet<String>(); //Creating set 

Adición de algunos elementos

actualSet.add("aaa"); 
actualSet.add("bbb"); 

Impresión añadió elementos

System.out.println(actualSet); //[aaa, bbb] 

Ponga la actualSet en conjunto no modificable y asignadas a nueva referencia (wrapperSet).

Set<String> wrapperSet=Collections.unmodifiableSet(orginalSet); 

Imprimir la wrapperSet. por lo que tendrá actualSet Valores

System.out.println(wrapperSet); //[aaa, bbb] 

permite tratar de eliminar/añadir un elemento de wrapperSet.

wrapperSet.remove("aaa"); //UnSupportedOperationException 

Añadir un elemento más en actualSet

actualSet .add("ccc"); 

Imprimir actualSet y wrapperSet. ambos conjuntos de valores son iguales. Entonces, si agrega/elimina cualquier elemento en el conjunto real, los cambios también se reflejarán en el conjunto contenedor.

System.out.println(actualSet); //[aaa, ccc, bbb] 
    System.out.println(wrapperSet); // [aaa, ccc, bbb] 

Uso:

Este Collections.unmodifiableSet(Set<? extends T>) se utiliza para evitar la modificación del método de obtención del Conjunto de cualquier objeto. digamos

public class Department{ 

    private Set<User> users=new HashSet<User>(); 

    public Set<User> getUsers(){ 
     return Collections.unmodifiableSet(users); 
    } 
}