开发者

What's the best way to detach a Collection from a Map in Java?

I obtain a HashSet from a HashMap and I don't want that my modifications on the HashSet reflect on the HashMap values开发者_JAVA百科.

What's the best way of doing something like this :

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 : I have to modify an element in the HashSet but I don't want to modify this same element in the HashMap.

Thanks!!!


If you're creating a new HashSet as per the first line of your code snippet, that's already a separate collection. Adding or removing items from the set won't change your hashMap. Modifying the existing items will, of course - but that's a different matter, and will almost always be a Very Bad Thing (assuming your modifications affect object equality).


When you create the HashSet from hashMap.values() like this, then it's already "detached" in the sense that modifying the HashSet will not influence the map it was constructed from.

However, if you modify an object inside the set (for example calling a setter on it), then those changes will be reflected inside the HashMap as well (since the Set and the Map will refer to the same object).

One way around this is to make defensive copies of each element (using clone() or by using a copy constructor).

Another way is to use immutable objects.


You are close:

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);


If you are trying to copy the values, and change the state of the values you need to create a deep copy, which relies on knowing how to create copies of the objects held in the Map as values. Hopefuly this test illustrates what I mean.

@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;
    }
}


Try this:

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));
    }
}

That said, I would be very careful about making copies of objects unless all the attributes of the object are primitive/immutable types. If you just copy an attribute object reference to an object reference in the clone then your 'clone' can still produce side-effects in the original object by changing the objects it references.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜