Qu'est-ce que Collections.unmodifiableSet () ne en Java?
-
19-09-2019 - |
Question
Je peux voir que Collections.unmodifiableSet
retourne une vue non modifiable de l'ensemble donné, mais je ne comprends pas pourquoi nous ne pouvons pas utiliser le modificateur de final
pour accomplir cette tâche.
Dans ma compréhension, final
déclare une constante: quelque chose qui ne peut être modifié. Donc, si un ensemble est déclaré comme une constante, alors il ne peut pas être modifié. Rien ne peut être retiré de l'ensemble et rien ne peut être ajouté
Pourquoi avons-nous besoin Collections.unmodifiableSet
?
La solution
final
déclare une référence d'objet qui ne peut être modifié, par exemple.
private final Foo something = new Foo();
crée un nouveau Foo
et place la référence en something
. Par la suite, il est impossible de modifier something
pour pointer vers une autre instance de Foo
.
Cela ne pas empêcher la modification de l'état interne de l'objet. Je peux encore appeler toutes les méthodes sur Foo
il y a accès à la portée pertinente. Si un ou plusieurs de ces méthodes modifie l'état interne de cet objet, alors final
n'empêchera pas que.
En tant que tel, ce qui suit:
private final Set<String> fixed = new HashSet<String>();
ne pas créer une Set
qui ne peut être ajouté ou autrement modifié; cela signifie simplement que fixed
ne jamais faire référence à cette instance.
Par contre, en faisant:
private Set<String> fixed = Collections.unmodifiableSet( new HashSet<String>() );
crée une instance d'un Set
qui jetteront UnsupportedOperationException
si l'on tente d'appeler fixed.add()
ou fixed.remove()
, par exemple -. L'objet lui-même protégera son état interne et l'empêcher d'être modifié
Pour être complet:
private final Set<String> fixed = Collections.unmodifiableSet( new HashSet<String>() );
crée une instance d'un Set
qui ne permettra pas son état interne à changer, et signifie aussi que fixed
ne jamais pointer vers une instance de cet ensemble.
La raison pour laquelle final
peut être utilisé pour créer des constantes de primitives est basée sur le fait que la valeur ne peut être modifiée. Rappelez-vous que fixed
ci-dessus était une référence - une variable contenant une adresse qui ne peut pas être changé. Eh bien, pour les primitives, par exemple.
private final int ANSWER = 42;
la valeur de ANSWER
est que 42. ANSWER
ne peut pas être changé, il ne jamais avoir la valeur 42.
Un exemple qui brouille toutes les lignes serait ceci:
private final String QUESTION = "The ultimate question";
Par les règles ci-dessus, QUESTION
contient l'adresse d'une instance de String
qui représente « La question ultime », et cette adresse ne peut pas être changé. La chose à retenir ici est que String
lui-même est immuable - vous ne pouvez pas faire quoi que ce soit à une instance de String
qui change, et toutes les opérations qui seraient autrement le faire (comme replace
, substring
, etc.) renvoient des références à tout autre cas de String
.
Autres conseils
final
ne garantit que la référence à l'objet la variable ne peut être analysé changé il ne fait rien pour l'instance de l'objet et sa mutabilité.
final Set s = new Set();
garantit que vous ne pouvez pas faire s = new Set();
à nouveau. Il ne fait pas l'ensemble non modifiable, si vous avez pas pu ajouter quelque chose pour commencer. Donc, pour le rendre vraiment clair, final
affecte uniquement la variable référence pas l'objet les points de référence.
Je peux faire ce qui suit:
final List<String> l = new ArrayList<String>();
l.add("hello");
l.add("world");
l.remove(0);
mais je ne peux pas le faire.
l = new ArrayList<String>();
à nouveau à cause de la final
Je ne peux pas modifier ce que les points de l variable à.
vous devez faire l'une des trois choses suivantes pour un fil de conteneur de collecte en toute sécurité.
java.util.Collections.syncronizedXXX();
ou
java.util.Collections.unmodifiableXXX();
ou
utiliser l'un des récipients appropriés à partir java.util.concurrency.* package
.
si j'avais un objet Person
et fait final Person p = new Person("me");
cela signifie que je ne peux pas réattribuer p
pour pointer vers un autre objet Person
. Je peux encore faire p.setFirstName("you");
Qu'est-ce que rend la situation confuse est que
final int PI = 3.14;
final String greeting = "Hello World!";
ressembler const
en C ++, alors qu'en fait les objets qu'ils pointent vers sont immuables / non modifiable par la nature. Des conteneurs ou des objets avec des méthodes mutator qui peuvent modifier l'état interne de l'objet ne sont pas const
uniquement la référence à ces objets sont final
et ne peuvent être réaffectés à référence un autre objet .
final
n'est pas (C ++ - style) const
. Contrairement à C ++, Java ne pas const
-méthodes ou quelque chose comme ça, et les méthodes qui peuvent changer l'objet peut être appelé via une référence final
.
Collections.unmodifiable*
est une enveloppe qui applique (au moment de l'exécution, et non au moment de la compilation), la lecture seule Etreté de collecte concerné.
Le Collections.unmodifiableSet(Set<? extends T>)
va créer wrapper sur l'ensemble original. Cet ensemble d'emballage ne peut pas être modifié. mais le jeu original peut être modifié.
Exemple:
Set<String> actualSet=new HashSet<String>(); //Creating set
Ajout des éléments
actualSet.add("aaa");
actualSet.add("bbb");
Impression ajoutée éléments
System.out.println(actualSet); //[aaa, bbb]
Mettre le actualSet
en jeu non modifiable et affecté à une nouvelle référence (wrapperSet
).
Set<String> wrapperSet=Collections.unmodifiableSet(orginalSet);
Imprimer la wrapperSet. il aura des valeurs de actualSet
System.out.println(wrapperSet); //[aaa, bbb]
permet d'essayer de supprimer / ajouter un élément sur wrapperSet
.
wrapperSet.remove("aaa"); //UnSupportedOperationException
Ajouter un élément supplémentaire dans actualSet
actualSet .add("ccc");
Imprimer actualSet
et wrapperSet
. Les deux ensembles de valeurs sont les mêmes. Donc, si vous ajoutez / supprimer tous les éléments sur jeu réel les changements seront pris en compte sur l'encapsuleur ainsi.
System.out.println(actualSet); //[aaa, ccc, bbb]
System.out.println(wrapperSet); // [aaa, ccc, bbb]
Utilisation:
Collections.unmodifiableSet(Set<? extends T>)
est utilisé pour empêcher la modification de la méthode de lecture de jeu de tout objet. Disons que
public class Department{
private Set<User> users=new HashSet<User>();
public Set<User> getUsers(){
return Collections.unmodifiableSet(users);
}
}
Résumer que nous pouvons faire et ne peut pas:
Préparation:
private Set<String> words = new HashSet<>(Arrays.asList("existing word"));
finale par référence
private final Set<String> words = new HashSet<>();
peut :
words.add("new word");
ne peut pas :
words = new HashSet<>(); //compilation error
Finale par référence et par collection. non modifiable
finale privée Set mots = Collections.unmodifiableSet (mots);
peut :
String word = words.iterator().next();
ne peut pas :
words = new HashSet<>(); // compilation error
words.add("new word"); // runtime error UnsupportedOperationException
Finale par référence et non modifiables par collection mais mutuels comme objet de collection.
Mais si vous avez la collection avec objets mutuelle, vous pouvez changer l'état interne de cet objet.
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)));
ne peut toujours pas
set = new HashSet<>(); // compilation error
set.add(new A(777)); // runtime error UnsupportedOperationException
Mais peut
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