2010-09-16 62 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)); 
    } 
} 

這就是說,我會非常小心,除非對象的所有屬性都是原始/穩定的類型製作對象的副本。如果您只是將屬性對象引用複製到克隆中的對象引用,那麼通過更改其引用的對象,您的「克隆」仍可以在原始對象中產生副作用。

相關問題