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?

Était-ce utile?

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
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top