example - order list object java
¿Qué hace Collections.unmodifiableSet() en Java? (5)
El Collections.unmodifiableSet(Set<? extends T>)
creará un contenedor en el set original. Este conjunto de envoltorio no puede ser modificado. pero aún así el conjunto original puede ser modificado.
Ejemplo:
Set<String> actualSet=new HashSet<String>(); //Creating set
Añadiendo algunos elementos.
actualSet.add("aaa");
actualSet.add("bbb");
Imprimiendo elementos añadidos
System.out.println(actualSet); //[aaa, bbb]
Coloque el actualSet
en un conjunto no modificable y asignado a una nueva referencia ( wrapperSet
).
Set<String> wrapperSet=Collections.unmodifiableSet(orginalSet);
Imprimir el wrapperSet. por lo que tendrá valores actualSet
System.out.println(wrapperSet); //[aaa, bbb]
intentemos eliminar / agregar un elemento en wrapperSet
.
wrapperSet.remove("aaa"); //UnSupportedOperationException
Añadir un elemento más en actualSet
actualSet .add("ccc");
Imprimir actualSet
y wrapperSet
. Ambos valores de conjunto son iguales. así que si agrega / elimina elementos en el conjunto real, los cambios también se reflejarán en el conjunto de envoltura.
System.out.println(actualSet); //[aaa, ccc, bbb]
System.out.println(wrapperSet); // [aaa, ccc, bbb]
Uso:
Este Collections.unmodifiableSet(Set<? extends T>)
se usa para evitar la modificación del método getter de Set de cualquier objeto. Digamos
public class Department{
private Set<User> users=new HashSet<User>();
public Set<User> getUsers(){
return Collections.unmodifiableSet(users);
}
}
Puedo ver que Collections.unmodifiableSet
devuelve una vista no modificable del conjunto dado, pero no entiendo por qué no podemos usar el modificador final
para lograr esto.
En mi entendimiento, final
declara una constante: algo que no puede ser modificado. Por lo tanto, si un conjunto se declara como una constante, entonces no se puede modificar: no se puede eliminar nada del conjunto y no se puede agregar nada.
¿Por qué necesitamos Collections.unmodifiableSet
?
Resuma que podemos hacer y no podemos:
Preparación:
private Set<String> words = new HashSet<>(Arrays.asList("existing word"));
Final por referencia
private final Set<String> words = new HashSet<>();
puede :
words.add("new word");
no puedo
words = new HashSet<>(); //compilation error
Final por referencia y no modificable por colección.
Set final privado de palabras = Colecciones.unmodifiableSet (palabras);
puede :
String word = words.iterator().next();
no puedo
words = new HashSet<>(); // compilation error
words.add("new word"); // runtime error UnsupportedOperationException
Final por referencia y no modificable por colección pero mutuo como objeto de colección.
Pero si tiene la colección con objetos mutual , puede CAMBIAR el estado interno de ese objeto.
class A {
public int a; //mutable field. I can change it after initialization
public A(int a) {this.a = a;}
}
private final Set<A> set = Collections.unmodifiableSet(Arrays.asList(new A(25)));
Todavia no puedo
set = new HashSet<>(); // compilation error
set.add(new A(777)); // runtime error UnsupportedOperationException
Pero puede
A custom = words.iterator().next(); //here custom.a = 25;
custom.a = 777; //here first element of **final, unmodifible** collection
//was changed from 25 to 777
final
declara una referencia de objeto que no se puede modificar, por ejemplo,
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 señalar una instancia diferente de Foo
.
Esto no impide la modificación del estado interno del objeto. Todavía puedo llamar a cualquier método en Foo
que esté disponible para el ámbito relevante. Si uno o más de esos métodos modifican el estado interno de ese objeto, entonces final
no lo impedirá.
Como tal, lo siguiente:
private final Set<String> fixed = new HashSet<String>();
no crea un Set
que no se pueda agregar o modificar de otra manera; solo significa que lo 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 lanzará UnsupportedOperationException
si uno intenta llamar a fixed.add()
o fixed.remove()
, por ejemplo: el objeto en sí protegerá su estado interno y evitará que se modifique.
Para la integridad:
private final Set<String> fixed = Collections.unmodifiableSet( new HashSet<String>() );
crea una instancia de un Set
que no permitirá que se cambie su estado interno, y también significa que fixed
solo apuntará a una instancia de ese conjunto.
La razón por la que se puede usar final
para crear constantes de primitivas se basa en el hecho de que el valor no se puede cambiar. Recuerde que lo anterior fue solo una referencia, una variable que contiene una dirección que no se puede cambiar. Bueno, para primitivos, por ejemplo,
private final int ANSWER = 42;
el valor de ANSWER
es 42. Como ANSWER
no se puede cambiar, solo tendrá el valor 42.
Un ejemplo que desenfoca todas las líneas sería este:
private final String QUESTION = "The ultimate question";
De acuerdo con las reglas anteriores, la 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
sí mismo es inmutable: no se puede hacer nada con una instancia del String
que lo cambia, y las operaciones que lo harían (como replace
, substring
, etc.) devuelven las referencias a diferentes instancias de String
.
final
no es (estilo C ++) const
. A diferencia de C ++, Java no tiene métodos const
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 (solo en tiempo de ejecución, no en tiempo de compilación) la capacidad de solo lectura de la colección en cuestión.
final
solo garantiza que la referencia al objeto que representa la variable no se puede cambiar, no hace nada por la instancia del objeto y su mutabilidad.
final Set s = new Set();
solo garantiza que no puedes hacer s = new Set();
de nuevo. No hace que el conjunto no sea modificable, si no pudieras agregarle nada para empezar. Entonces, para que quede realmente claro, la final
solo afecta a la referencia de variable, no al objeto al que apunta la referencia.
Puedo 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>();
otra vez debido a la final
no puedo modificar a qué apunta la variable l.
Tiene que hacer una de las siguientes tres cosas para hacer que un subproceso de contenedor de la colección sea seguro.
java.util.Collections.syncronizedXXX();
o
java.util.Collections.unmodifiableXXX();
o use uno de los contenedores apropiados del java.util.concurrency.* package
.
si tuviera un objeto Person
y lo hiciera final Person p = new Person("me");
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!";
Parecen const
en C ++, cuando en realidad los objetos a los que apuntan son inmutables / no modificables por naturaleza. Los contenedores u objetos con métodos de mutación que pueden alterar el estado interno del objeto no son const
solo que la referencia a esos objetos es final
y no se puede reasignar para hacer referencia a otro objeto.