java HashMap.putall是否克隆所有元素?
我有一个Hashmap,我在其中编写了一个类,用于添加和检索值java HashMap.putall是否克隆所有元素?,java,hashmap,cloning,Java,Hashmap,Cloning,我有一个Hashmap,我在其中编写了一个类,用于添加和检索值 class ReputationMatrix { private HashMap < Integer, int[] > repMatrix; public ReputationMatrix() { repMatrix = new HashMap < Integer, int[] > (); } public void addrating(int no
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;
}
}
结果是:
2
2
3
3
这意味着我对matrix1所做的每一个改变都会反映在matrix2上。
我几乎可以肯定putAll确实创建了副本。我做错了什么?来自:
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)));
putAll
不会创建键和值的副本。它为传递给它的每个键/值对调用put
,并且put
不会创建副本。否,putAll()
不会将元素克隆到映射。它只是将引用复制到它们,这样就有两个引用变量指向堆中的同一个对象。这称为浅复制。如果要克隆所有元素(deepcopy),必须执行以下操作:
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));
}
}
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());
}
Map original=newhashmap();
Map clone=new HashMap();
for(Map.Entry:original.entrySet){
clone.put(entry.getKey(),entry.getValue().clone());
}
如您所见,没有副本
/**
* 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());
}
}
/**
*将指定映射中的所有映射复制到此映射。
*这些映射将替换此映射用于的所有映射
*指定映射中当前的任何键。
*
*@param m要存储在此映射中的映射
*@如果指定的映射为null,则会引发NullPointerException
*/
public void putAll(MapJava中没有深度副本。如果需要,必须通过递归调用clone()
对其进行编码
还要注意,数组是对象,因此int[]
in
private HashMap < Integer, int[] > repMatrix;
.putAll()
从不进行“深度复制”;它只做浅拷贝。你从哪里读到它做了深拷贝?put和putall只存储对对象的引用。也许当时我错了。所以我克隆Hashmap的唯一方法是循环遍历所有键并克隆数组?在Java中,你永远不会自动获得拷贝,它必须是显式的。这有一个根本原因:复制对象图是一个定义不正确的概念,在一般情况下无法解决。您是指entry.get[Key | Value].clone(),是吗?是的!谢谢您的提示:)我只需要克隆值,使用与实际使用的密钥散列相同的密钥没有问题。如果您解释代码中证明没有创建副本的部分,这将是一个很好的答案。我有以下数据集HashMap
,当我使用putAll时,我看起来像是复制的对象而不是值。因为第一个的变化会影响第二个
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());
}
private HashMap < Integer, int[] > repMatrix;
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
}