Je peux voir que Collections.unmodifiableSet
renvoie une vue non modifiable de l’ensemble donné, mais je ne comprends pas pourquoi nous ne pouvons pas simplement utiliser le modificateur final
pour accomplir cela.
Dans ma compréhension, final
déclare une constante: quelque chose qui ne peut pas être modifié. Ainsi, si un ensemble est déclaré en tant que constante, il ne peut pas être modifié: rien ne peut être supprimé de l’ensemble et rien ne peut être ajouté.
Pourquoi avons-nous besoin de Collections.unmodifiableSet
?
final
déclare une référence d’object qui ne peut pas être modifiée, par exemple
private final Foo something = new Foo();
crée un nouveau Foo
et place la référence dans something
. Par la suite, il est impossible de modifier something
pour pointer vers une instance différente de Foo
.
Cela n’empêche pas la modification de l’état interne de l’object. Je peux toujours appeler toutes les méthodes disponibles sur Foo
sont accessibles au périmètre concerné. Si une ou plusieurs de ces méthodes modifient l’état interne de cet object, final
n’empêchera pas cela.
À ce titre, les éléments suivants:
private final Set fixed = new HashSet ();
ne crée pas un Set
qui ne puisse pas être ajouté ou modifié; cela signifie simplement que fixed
ne fera jamais référence à cette instance.
En revanche, en faisant:
private Set fixed = Collections.unmodifiableSet( new HashSet () );
crée une instance d’un Set
qui fixed.add()
si l’on tente d’appeler fixed.add()
ou fixed.remove()
, par exemple: l’object lui-même protégera son état interne et l’empêchera d’être modifié.
Par souci d’exhaustivité:
private final Set fixed = Collections.unmodifiableSet( new HashSet () );
crée une instance d’un Set
qui ne permet pas la modification de son état interne, mais signifie également que « fixed
pointe uniquement sur 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 pas être modifiée. Rappelez-vous que la fixed
ci-dessus n’était qu’une référence – une variable contenant une adresse non modifiable. Eh bien, pour les primitives, par exemple
private final int ANSWER = 42;
la valeur de ANSWER
est celle 42. Puisque la ANSWER
ne peut pas être modifiée, elle n’aura jamais que la valeur 42.
Voici un exemple qui brouille toutes les lignes:
private final Ssortingng QUESTION = "The ultimate question";
Selon les règles ci-dessus, QUESTION
contient l’adresse d’une instance de Ssortingng
qui représente “la question ultime” et cette adresse ne peut pas être modifiée. Ce qu’il faut retenir ici, c’est que Ssortingng
lui-même est immuable – vous ne pouvez rien faire avec une instance de Ssortingng
qui le modifie, et toute opération qui le ferait autrement (comme le replace
, la subssortingng
– subssortingng
, etc.) renvoie des références entièrement différentes. instances de Ssortingng
.
final
garantit uniquement que la référence à l’object représenté par la variable ne peut pas être modifiée; il ne fait rien pour l’instance de l’object et sa mutabilité.
final Set s = new Set();
garantit simplement que vous ne pouvez pas faire s = new Set();
encore. Cela ne rend pas le jeu non modifiable, mais si vous ne pouviez rien y append pour commencer. Donc, pour que ce soit vraiment clair, final
n’affecte que la variable référence, pas l’object sur lequel la référence pointe.
Je peux faire ce qui suit:
final List l = new ArrayList (); l.add("hello"); l.add("world"); l.remove(0);
mais je ne peux pas faire ça.
l = new ArrayList();
encore une fois à cause de la final
je ne peux pas modifier le sens de la variable l.
vous devez effectuer l’une des trois opérations suivantes pour sécuriser un thread de conteneur Collection.
java.util.Collections.syncronizedXXX();
ou
java.util.Collections.unmodifiableXXX();
ou utilisez l’un des conteneurs appropriés du java.util.concurrency.* package
.
si j’avais un object Person
et si j’ai fait une Person
final Person p = new Person("me");
cela signifie que je ne peux pas réaffecter p
pour qu’il pointe vers un autre object Person
. Je peux toujours faire p.setFirstName("you");
Ce qui confond la situation est que
final int PI = 3.14; final Ssortingng greeting = "Hello World!";
ressemblent à const
en C ++, alors que les objects qu’ils désignent sont immuables / non modifiables par nature. Les conteneurs ou les objects utilisant des méthodes de mutateur pouvant modifier l’état interne de l’object ne sont pas const
mais la référence à ces objects est final
et ne peut pas être réaffectée pour référencer un autre object.
final
n’est pas (style C ++) const
. Contrairement à C ++, Java n’a pas de méthodes const
ou quoi que ce soit d’autre, et les méthodes qui peuvent changer l’object peuvent être appelées via une référence final
.
Collections.unmodifiable*
est un wrapper qui applique (au moment de l’exécution uniquement, pas au moment de la compilation) la lecture seule de la collection concernée.
Collections.unmodifiableSet(Set extends T>)
créera un wrapper sur le jeu d’origine. Cet ensemble de wrapper ne peut pas être modifié. mais encore le jeu original peut être modifié.
Exemple:
Set actualSet=new HashSet (); //Creating set
Ajout de quelques éléments
actualSet.add("aaa"); actualSet.add("bbb");
Impression d’éléments ajoutés
System.out.println(actualSet); //[aaa, bbb]
Placez le actualSet
dans un ensemble non modifiable et atsortingbuez-le à une nouvelle référence ( wrapperSet
).
Set wrapperSet=Collections.unmodifiableSet(orginalSet);
Imprimez le wrapperSet. donc il aura des valeurs actualSet
System.out.println(wrapperSet); //[aaa, bbb]
Essayons de supprimer / append un élément sur wrapperSet
.
wrapperSet.remove("aaa"); //UnSupportedOperationException
Ajouter un élément de plus dans actualSet
actualSet .add("ccc");
Imprimer actualSet
et wrapperSet
. les deux valeurs sont identiques. donc, si vous ajoutez / supprimez des éléments sur le jeu réel, les modifications seront également répercutées sur le jeu de wrappers.
System.out.println(actualSet); //[aaa, ccc, bbb] System.out.println(wrapperSet); // [aaa, ccc, bbb]
Usage:
Collections.unmodifiableSet(Set extends T>)
est utilisé pour empêcher la modification de la méthode d’accesseur de Set pour tout object. disons
public class Department{ private Set users=new HashSet (); public Set getUsers(){ return Collections.unmodifiableSet(users); } }
Résumez ce que nous pouvons faire et ne pouvons pas:
Préparation:
private Set words = new HashSet<>(Arrays.asList("existing word"));
private final Set words = new HashSet<>();
peut :
words.add("new word");
ne peut pas :
words = new HashSet<>(); //compilation error
private final Set words = Collections.unmodifiableSet (mots);
peut :
Ssortingng word = words.iterator().next();
ne peut pas :
words = new HashSet<>(); // compilation error words.add("new word"); // runtime error UnsupportedOperationException
Mais si vous avez la collection avec des objects mutuels , vous pouvez CHANGER l’état intérieur de cet object.
class A { public int a; //mutable field. I can change it after initialization public A(int a) {this.a = a;} } private final Set set = Collections.unmodifiableSet(Arrays.asList(new A(25)));
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