Java HashMap:JVM中的一个Bug还是我做错了?

时间:2014-12-06 20:44:50

标签: java hashmap

在下面的代码中: -

  1. 创建HashMap并添加一些元素。
  2. 使用第一个映射创建第二个HashMap。
  3. 修改第二个HashMap。
  4. 第一个HashMap与?

    一起被修改
    public static void test(){
        HashMap<Integer, ArrayList<Integer>> testData = new HashMap<Integer, ArrayList<Integer>> ();
        testData.put(1, new ArrayList<Integer>(Arrays.asList(777)));
        System.out.println(testData);
        HashMap<Integer,ArrayList<Integer>> testData1 = new HashMap<Integer, ArrayList<Integer>> (testData);
        testData1.get(1).add(888);
        System.out.println(testData);
    }
    
  5. 输出:

    {1=[777]}
    {1=[777, 888]}
    

    在此处试试:Code on Ideone.com

    我希望testData和testData1彼此独立,但看起来它们都引用同一个对象?它是用于Java吗?我做错了吗?

2 个答案:

答案 0 :(得分:3)

您正在制作原始HashMap浅层副本: 复制列表引用,然后复制它们的项目。

您需要自己执行深层复制

    HashMap<Integer, List<Integer>> testData = new HashMap<>();
    testData.put(1, new ArrayList<>(Arrays.asList(777)));

    HashMap<Integer, List<Integer>> testData = new HashMap<>();
    testData.put(1, Arrays.asList(777));

    HashMap<Integer, List<Integer>> testData2 = new HashMap<>();
    for (Map.Entry<Integer, List<Integer>> entry : testData.entrySet()) {
        testData2.put(entry.getKey(), new ArrayList<>(entry.getValue()));
    }
    testData2.get(1).add(888);
    System.out.println(testData);
    System.out.println(testData2);

打印:

{1=[777]}
{1=[777, 888]}

正如@jon-kiparsky在评论中解释得很好:

  

这可能是显而易见的,但仅仅是为了完整性:由于HashMap存储对象而不是基元,因此地图存储对对象的引用。这就是为什么你需要考虑深度和浅层副本。

作为旁注,我还改进了您的示例代码:

  • 在声明中使用接口类型而不是实现类型
  • 无需将Arrays.asList(...)包裹在new ArrayList<>(...)
  • 在Java 7中使用菱形运算符<>(因此不再使用Java 7或更高版本,因为不再支持旧版本)。

答案 1 :(得分:0)

java中的所有集合都包含对象的引用。因此,当您从第二个映射修改列表时,它正在修改列表

的同一对象