2010-09-16 2 views
0

J'obtiens un HashSet d'une HashMap et je ne veux pas que mes modifications sur le HashSet reflètent les valeurs de HashMap.Quelle est la meilleure façon de détacher une collection d'une carte en Java?

Quelle est la meilleure façon de faire quelque chose comme ceci:

HashSet<Object> hashset = new HashSet((Collection<Object>) hashmap.values()); 
//Something like ... 
hashset.detach(); 
//Then i can modify the HashSet without modifying the HashMap values 

Edit: Je dois modifier un élément dans le HashSet mais je ne veux pas modifier ce même élément dans le HashMap.

Merci !!!

Répondre

4

Lorsque vous créez le HashSet de hashMap.values() comme ça, alors il est déjà « détaché » dans le sens que la modification du HashSet n'influencera pas la carte, il a été construit à partir.

Cependant, si vous modifiez un objet intérieur l'ensemble (par exemple appeler un setter sur lui), alors ces changements seront reflétés dans le HashMap ainsi (depuis le Set et la Map se référera au même objet). Une solution consiste à créer defensive copies pour chaque élément (en utilisant clone() ou en utilisant un constructeur de copie). Un autre moyen consiste à utiliser immutable objects.

+0

L'utilisation de clone() ou new HashSet (objet) ne fonctionne pas .. la modification d'un élément est reflétée dans la HashMap. – codea

+1

@elbanco: Je voulais dire que vous utilisiez 'clone()' sur * chaque élément de 'Set' *. Si vous ne clonez que le 'Set' lui-même, cela n'aura aucun effet. –

+0

ok ... Je vais essayer après le déjeuner. – codea

6

Si vous créez un nouveauHashSet selon la première ligne de votre extrait de code, il s'agit déjà d'une collection distincte. L'ajout ou la suppression d'éléments de l'ensemble ne changera pas votre hashMap. La modification des éléments existants sera, bien sûr - mais c'est une question différente, et sera presque toujours une très mauvaise chose (en supposant que vos modifications affectent l'égalité des objets).

1

Vous êtes à proximité:

Set<Object> set = hashmap.values(); // is backed by the map 

// create a new hashset seeded from the other set 
Set<Object> hashset = new HashSet<Object>(set); 
+0

Cela ne fonctionne pas .. la modification d'un élément est reflétée dans le HashMap. – codea

+0

Ensuite, vous changez d'éléments dans l'ensemble (plutôt que de changer * quels * éléments sont dans l'ensemble). Pour cela, vous devez copier chaque élément dans le nouvel ensemble, comme d'autres l'ont dit. –

0

Si vous essayez de copier les valeurs et que vous modifiez l'état des valeurs, vous devez créer une copie en profondeur qui repose sur la façon de créer des copies des objets contenus dans Map en tant que valeurs. Espérons que ce test illustre ce que je veux dire.

@Test 
public void testHashMap() throws Exception { 
    final Map<Integer, TestContainer<Double>> hashmap = new HashMap<Integer, TestContainer<Double>>(); 
    final TestContainer<Double> t1 = new TestContainer<Double>(1d); 
    final TestContainer<Double> t2 = new TestContainer<Double>(2d); 
    hashmap.put(1, t1); 
    hashmap.put(2, t2); 

    // create a separate collection which can be modified 
    final Set<TestContainer<Double>> hashset = new HashSet<TestContainer<Double>>(hashmap.values()); 
    assertEquals(2, hashmap.size()); 
    assertEquals(2, hashset.size()); 

    hashset.remove(t2); 

    assertEquals(2, hashmap.size()); 
    assertEquals(1, hashset.size()); 

    // prove that we cannot modify the contents of the collection 
    hashset.iterator().next().o += 1; 

    assertEquals(2d, t1.o, 0d); 
} 

private static final class TestContainer<T> { 
    private T o; 

    private TestContainer(final T o) { 
     this.o = o; 
    } 
} 
0

Essayez ceci:

public MyType cloneObject(MyType o) { 
    MyType clone = new MyType(); 
    // TODO copy the attributes of 'o' to 'clone' return the clone 
    return clone; 
} 

public void populateHashSet(HashMap<Object,MyType> hashMap) { 
    HashSet<MyType> hashSet = new HashSet<MyType>(); 
    for (MyType o : hashMap.values()) { 
     hashSet.add(cloneObject(o)); 
    } 
} 

Cela dit, je serais très prudent de faire des copies d'objets à moins que tous les attributs de l'objet sont primitifs/types immuables. Si vous copiez simplement une référence d'objet attribut à une référence d'objet dans le clone, alors votre 'clone' peut encore produire des effets secondaires dans l'objet original en changeant les objets qu'il référence.

Questions connexes