我有一个Hashmap,我在其中编写了一个处理添加和检索值的类。
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
这意味着我应用于matrix1的每个更改都反映在matrix2上。 我几乎肯定putAll确实创建副本。我做错了什么?
答案 0 :(得分:4)
<强>的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]
答案 1 :(得分:1)
putAll
不会创建密钥和值的副本。它会为传递给它的每个键/值对调用put
,而put
不会创建副本。
答案 2 :(得分: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());
}
答案 3 :(得分: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放到我们的地图上。
答案 4 :(得分: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
}