Java HashMap.putall clone all elements?

I have a Hashmap in which I wrote a class that deals with adding and receiving values.

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

I implemented a cloning method to simply return a separate copy of ReputationMatrix completely independent of the original.

I tested the code as follows:

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

the conclusion was:

2
2
3
3

This means that every change that I apply to matrix 1 is reflected in matrix2. I am pretty sure putAll creates copies. What am I doing wrong?

+4
source share
5 answers

From the documentation :

putAll

( ). put (k, v) 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]
+3

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

, .

 /**
 * 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());
    }
} 

src openjdk.

 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 .

0

Java . , , clone() .

, , int[]

private HashMap < Integer, int[] > repMatrix;

is an array reference int. When you get this array in addRating(), hashmap still contains a reference to the array, and there is no need put()after modification

    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
    }
0
source

All Articles