Java HashMap:JVM中的错误还是我做错了?

Java HashMap:JVM中的错误还是我做错了?,java,hashmap,Java,Hashmap,在下面的代码中:- 创建HashMap并添加一些元素 创建第二个HashMap,使用第一个HashMap的映射 修改第二个HashMap 第一个HashMap随?一起修改 public static void test(){ HashMap<Integer, ArrayList<Integer>> testData = new HashMap<Integer, ArrayList<Integer>> (); testData.put

在下面的代码中:-

  • 创建HashMap并添加一些元素
  • 创建第二个HashMap,使用第一个HashMap的映射
  • 修改第二个HashMap
  • 第一个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);
    }
    
    请在此处尝试:

    我希望testData和testData1彼此独立,但它们似乎都引用了同一个对象?它是用Java编写的吗?我做错什么了吗?

    您正在对原始的
    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);
    
    正如在一篇评论中很好地解释的:


    这可能很明显,但只是为了完整性:因为HashMap存储对象,而不是原语,所以您的映射存储对对象的引用。这就是为什么你需要从深层和浅层的角度来思考

    另外,我还改进了您的示例代码:

    • 在声明中使用接口类型,而不是实现类型
    • 无需将
      数组.asList(…)
      包装在
      新数组列表(…)
    • 在Java 7中使用菱形操作符
      (因此,使用Java 7或更高版本,因为不再支持旧版本)
      • 您正在制作原始
        哈希映射的浅拷贝:
        复制列表引用,然后复制它们的项

        您需要自己进行深度复制:

            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);
        
        正如在一篇评论中很好地解释的:


        这可能很明显,但只是为了完整性:因为HashMap存储对象,而不是原语,所以您的映射存储对对象的引用。这就是为什么你需要从深层和浅层的角度来思考

        另外,我还改进了您的示例代码:

        • 在声明中使用接口类型,而不是实现类型
        • 无需将
          数组.asList(…)
          包装在
          新数组列表(…)
        • 在Java 7中使用菱形操作符
          (因此,使用Java 7或更高版本,因为不再支持旧版本)

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

        是的,它是有意的。地图只存储参考,而不是对象。哦!这意味着两个贴图对象但包含相同的ArrayList?如何解决这个问题?是否需要手动创建阵列的另一个副本?克隆不是制作ArrayList的新副本。同样的问题持续存在,这是有意的。地图只存储参考,而不是对象。哦!这意味着两个贴图对象但包含相同的ArrayList?如何解决这个问题?是否需要手动创建阵列的另一个副本?克隆不是制作ArrayList的新副本。同样的问题持续存在这可能很明显,但只是为了完整性:因为HashMap存储对象,而不是原语,所以您的映射存储对对象的引用。这就是为什么你需要从深层和浅层的角度来思考。谢谢,我理解了。这对我来说有点不直观。所以Java中没有深度复制的速记?我的意思是必须有一个函数,它为对象和它所包含的对象进行复制谢谢@JonKiparsky,你说得太好了,我在我的答案中逐字逐句地包括了;-)@Java SDK中的MangatRai我不这么认为。在诸如Apache或Google的Guava之类的实用程序库中,可能有一些实用程序类可以简化这一过程。感谢您的建议……这可能是显而易见的,但只是为了完整性:因为HashMap存储对象,而不是原语,所以您的映射存储对对象的引用。这就是为什么你需要从深层和浅层的角度来思考。谢谢,我理解了。这对我来说有点不直观。所以Java中没有深度复制的速记?我的意思是必须有一个函数,它为对象和它所包含的对象进行复制谢谢@JonKiparsky,你说得太好了,我在我的答案中逐字逐句地包括了;-)@Java SDK中的MangatRai我不这么认为。在诸如Apache或Google的Guava之类的实用程序库中,可能有一些实用程序类可以简化这一过程。谢谢你的推荐。。。
        {1=[777]}
        {1=[777, 888]}