2015-04-08 53 views
4

我有一個HashMap,我寫了一個類來處理添加和檢索值。java java HashMap.putall clone所有元素?

class ReputationMatrix 
{ 
    private HashMap < Integer, int[] > repMatrix; 

    public ReputationMatrix() 
    { 
     repMatrix = new HashMap < Integer, int[] >(); 
    } 

    public void addrating(int nodeId, boolean rating) 
    { 
     int[] alphaBeta; 

     if (repMatrix.containsKey(nodeId)) 
     { 
      alphaBeta = repMatrix.get(nodeId); 

      if (rating == true) 
      { 
       alphaBeta[0] = alphaBeta[0] + 1; 
      } 
      else 
      { 
       alphaBeta[1] = alphaBeta[1] + 1; 
      } 

      repMatrix.put(nodeId, alphaBeta); 
     } 
     else 
     { 
      alphaBeta = new int[2]; 

      if (rating == true) 
      { 
       alphaBeta[0] = 2; 
       alphaBeta[1] = 1; 
      } 
      else 
      { 
       alphaBeta[0] = 1; 
       alphaBeta[1] = 2; 
      } 

      repMatrix.put(nodeId, alphaBeta); 

     } 
    } 

    public int[] getNodeIds() 
    { 
     int[] nodeIds = new int[repMatrix.size()]; 
     int index = 0; 

     for (int key: repMatrix.keySet()) 
     { 
      nodeIds[index] = key; 
      index++; 
     } 

     return nodeIds; 
    } 

    public int getAlpha(int nodeId) 
    { 
     return repMatrix.get(nodeId)[0]; 
    } 

    public int getBeta(int nodeId) 
    { 
     return repMatrix.get(nodeId)[1]; 
    } 

    public ReputationMatrix clone() 
    { 
     ReputationMatrix matrixClone = new ReputationMatrix(); 
     matrixClone.repMatrix.putAll(this.repMatrix); 
     return matrixClone; 
    } 
} 

我實現了一個克隆方法來簡單地返回完全獨立於原始的ReputationMatrix的單獨副本。

我測試像這樣的代碼:

public class Main 
{ 
    /** 
    * @param args 
    */ 
    public static void main(String[] args) 
    { 
     ReputationMatrix matrix1 = new ReputationMatrix(); 
     matrix1.addrating(18, true); 

     ReputationMatrix matrix2 = matrix1.clone(); 

     System.out.println(matrix1.getAlpha(18)); 
     System.out.println(matrix2.getAlpha(18)); 

     matrix1.addrating(18, true); 

     System.out.println(matrix1.getAlpha(18)); 
     System.out.println(matrix2.getAlpha(18)); 
    } 
} 

產量爲:

2 
2 
3 
3 

這意味着我適用於矩陣1是反射到矩陣2的每一個變化。 我幾乎可以肯定putAll會創建副本。我究竟做錯了什麼?

+1

'.putAll()'從來不「深副本」;它只做淺拷貝。你從哪裏讀到它的深度拷貝? – fge

+0

put和putall只是存儲對象的引用。 – Dan

+0

也許我錯了。因此,我可以克隆Hashmap的唯一方法是如果我遍歷所有密鑰並克隆數組? – user1378063

回答

3

documentation

的putAll

將所有從指定映射到此地圖(可選操作)的映射的。此調用的效果等同於在此映射上爲指定映射中的每個從鍵k到值v的映射調用put(k,v)的效果。

所以使對象的副本,它只是從原來的地圖,新地圖增加了映射。

做你想做什麼,你將需要在各個值明確複製:

Map<Integer, int[]> originalMatrix = new HashMap<>(); 
int[] original = {1, 2, 3}; 
originalMatrix.put(1, original); 
Map<Integer, int[]> newMatrix = new HashMap<>(); 

for (Map.Entry<Integer, int[]> entry : originalMatrix.entrySet()) { 
    newMatrix.put(entry.getKey(), entry.getValue().clone()); 
} 

Arrays.fill(original, 0); 

System.out.println(Arrays.toString(original)); 
System.out.println(Arrays.toString(newMatrix.get(1))); 

輸出:

[0, 0, 0] 
[1, 2, 3] 
+0

我有folllowing數據集'HashMap >>',當我使用putAll我看起來像複製對象不是一個值。因爲第一個影響第二個影響的變化 – murt

1

putAll不創建鍵和值的副本。它爲傳遞給它的每個鍵/值對調用put,並且put不創建副本。

1

不,putAll()不是將元素克隆到地圖。它只是複製對它們的引用,所以你有兩個引用變量指向堆中的同一個對象。這叫做拷貝。如果你想克隆的所有元素(副本),你必須做這樣的事情:

Map<K,V> original = new HashMap<K,V>(); 
Map<K,V> clone = new HashMap<K,V>(); 
for(Map.Entry<K,V> entry : original.entrySet) { 
    clone.put(entry.getKey(), entry.getValue().clone()); 
} 
+1

您的意思是entry.get [Key | Value] .clone(),是嗎? – Sibbo

+0

是的!感謝您的支持:)我只需要克隆該值,具有與實際使用的密鑰哈希相同的密鑰是沒有問題的。 –

0

正如你所看到的,沒有副本。

/** 
* Copies all of the mappings from the specified map to this map. 
* These mappings will replace any mappings that this map had for 
* any of the keys currently in the specified map. 
* 
* @param m mappings to be stored in this map 
* @throws NullPointerException if the specified map is null 
*/ 
public void putAll(Map<? extends K, ? extends V> m) { 
    int numKeysToBeAdded = m.size(); 
    if (numKeysToBeAdded == 0) 
     return; 

    /* 
    * Expand the map if the map if the number of mappings to be added 
    * is greater than or equal to threshold. This is conservative; the 
    * obvious condition is (m.size() + size) >= threshold, but this 
    * condition could result in a map with twice the appropriate capacity, 
    * if the keys to be added overlap with the keys already in this map. 
    * By using the conservative calculation, we subject ourself 
    * to at most one extra resize. 
    */ 
    if (numKeysToBeAdded > threshold) { 
     int targetCapacity = (int)(numKeysToBeAdded/loadFactor + 1); 
     if (targetCapacity > MAXIMUM_CAPACITY) 
      targetCapacity = MAXIMUM_CAPACITY; 
     int newCapacity = table.length; 
     while (newCapacity < targetCapacity) 
      newCapacity <<= 1; 
     if (newCapacity > table.length) 
      resize(newCapacity); 
    } 

    for (Iterator<? extends Map.Entry<? extends K, ? extends V>> i = m.entrySet().iterator(); i.hasNext();) { 
     Map.Entry<? extends K, ? extends V> e = i.next(); 
     put(e.getKey(), e.getValue()); 
    } 
} 

這是來自openjdk的原始src。

for (Iterator<? extends Map.Entry<? extends K, ? extends V>> i = m.entrySet().iterator(); i.hasNext();) { 
     Map.Entry<? extends K, ? extends V> e = i.next(); 
     put(e.getKey(), e.getValue()); 
    } 

我們只是把每個Key-Value放到我們的地圖上。

+0

如果你解釋了證明沒有創建副本的代碼部分,這將是一個很好的答案。 – CKing

+0

感謝您的評論!固定:) – RSCh

0

Java中沒有深層拷貝。如果你想要它,你必須遞歸地調用clone()來編碼它。

還要注意的是陣列因此int[]

private HashMap < Integer, int[] > repMatrix; 

對象是一個int陣列上的參考。當您在addRating()得到這個數組,HashMap中仍持有的陣列上的參考,而且也沒有必要修改put()

if (repMatrix.containsKey(nodeId)) { 
     alphaBeta = repMatrix.get(nodeId); 

     if (rating == true) { 
      alphaBeta[0] = alphaBeta[0] + 1; 
     } 
     else { 
      alphaBeta[1] = alphaBeta[1] + 1; 
     } 

     //repMatrix.put(nodeId, alphaBeta); <= not needed 
    }