在Java中从Map分离Collection的最佳方法是什么?

时间:2010-09-16 15:25:03

标签: java collections map

我从HashMap获取HashSet,我不希望我对HashSet的修改反映在HashMap值上。

做这样的事情的最佳方式是什么:

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

修改: 我必须修改HashSet中的一个元素,但我不想在HashMap中修改这个相同的元素。

感谢!!!

5 个答案:

答案 0 :(得分:6)

如果您根据代码段的第一行创建 new HashSet,那么这已经是一个单独的集合。在集合中添加或删除项目不会更改hashMap。当然,修改现有的项目 - 但这是另一回事,并且几乎总是非常糟糕(假设您的修改会影响对象相等)。

答案 1 :(得分:4)

当您从HashSet这样创建hashMap.values()时,它已经“分离”了,因为修改HashSet不会影响它构建的地图。

但是,如果您在中修改对象(例如在其上调用setter),那么这些更改也将反映在HashMap内(因为{{ 1}}和Set将引用同一个对象。)

解决此问题的一种方法是使每个元素defensive copies(使用Map或使用复制构造函数)。

另一种方法是使用immutable objects

答案 2 :(得分:1)

你很近:

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

答案 3 :(得分:0)

如果您尝试复制值,并更改创建深层副本所需的值的状态,这取决于知道如何创建Map中保存的对象的副本作为值。希望这个测试能说明我的意思。

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

答案 4 :(得分:0)

试试这个:

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

也就是说,除非对象的所有属性都是原始/不可变类型,否则我会非常小心地创建对象的副本。如果只是将属性对象引用复制到克隆中的对象引用,那么“克隆”仍然可以通过更改它引用的对象在原始对象中产生副作用。