2010-09-16 61 views
0

我从HashMap获得一个HashSet,我不希望对HashSet的修改反映在HashMap的值上。从Java地图中分离集合的最佳方式是什么?

什么是做这样的事情的最好方法:

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来修改此相同的元素。

谢谢!

回答

4

当您从hashMap.values()这样的HashSet,那么它已经“分离”在这个意义上修改HashSet不会影响它从构建地图。

但是,如果修改一个对象内部集合(例如对它调用一个setter),那么这些更改将在HashMap内部反射以及(因为SetMap将是指相同的对象)。

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

另一种方法是使用immutable objects

+0

使用clone()或新的HashSet (object)不起作用。元素的修改反映在HashMap中。 – codea 2010-09-16 15:55:07

+1

@elbanco:我的意思是你在'Set' *中的每个元素上使用'clone()'。如果你只克隆'Set'本身,那么这将不起作用。 – 2010-09-16 15:55:51

+0

好的...午餐后我会尝试一下。 – codea 2010-09-16 16:04:26

6

如果按照代码片段的第一行创建新的HashSet,那已经是一个单独的集合。添加或删除集合中的项目不会改变您的hashMap。当然,修改已有的项目 - 但这是一个不同的问题,并且几乎总是非常糟糕的事情(假设您的修改会影响对象相等性)。

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

它不起作用..元素的修改反映在HashMap中。 – codea 2010-09-16 15:53:28

+0

然后,您正在更改集合中的元素(而不是更改*中的哪些*元素)。正如其他人所说的那样,您需要将每个元素复制到新的集合中。 – 2010-09-16 15:56:15

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

这就是说,我会非常小心,除非对象的所有属性都是原始/稳定的类型制作对象的副本。如果您只是将属性对象引用复制到克隆中的对象引用,那么通过更改其引用的对象,您的“克隆”仍可以在原始对象中产生副作用。

相关问题