Map 是存储引用变量的副本还是对象的副本?

Does Map store copy of the reference variable or copy of the object?

提问人:BeastMaster64 提问时间:1/6/2022 更新时间:1/6/2022 访问量:807

问:

我有这个小代码片段,想知道是存储引用变量的副本还是对象的副本的实现。java.Util.Map

public static void main(String[] args) {
    List<Integer> obj = Arrays.asList(1,2,3);
    Map<Integer, List<Integer>> a = new HashMap<>();
    a.put(0, obj);
    a.get(0).forEach(System.out::print);
    obj = Arrays.asList(4,5,6);
    System.out.println();
    a.get(0).forEach(System.out::print);
}

输出

123
123

我有一种感觉,这个问题的答案一定已经存在了(好吧,它可能已经存在,但我找不到它),我阅读了以下答案,但对我的问题知之甚少

Java 是按引用还是按值返回

这个答案说,如果它是可变的,它可能会发生,但是它是可变的(java.util.List是可变的吗?),那么为什么它没有发生呢?IntegerArrayList

Java 集合 Hashmap 不可变性 按值传递

评论


答:

2赞 Turing85 1/6/2022 #1

首先:Arrays::asList 创建一个固定大小的列表。
第二条这条线

obj = Arrays.asList(4,5,6);

创建新的 List 对象

为了检验您的假设,我们需要创建一个可修改的列表,将其添加到地图中,然后修改列表:

public static void main(String[] args) {
  List<Integer> obj = new ArrayList<>(Arrays.asList(1,2,3));
  Map<Integer, List<Integer>> a = new HashMap<>();
  a.put(0, obj);
  a.get(0).forEach(System.out::print);
  obj.clear();
  obj.add(4);
  obj.add(5);
  obj.add(6);
  System.out.println();
  a.get(0).forEach(System.out::print);
}

Ideone demo

我们看到以下输出:

123
456

这确认地图不会复制列表,而只是保留对列表的引用。

评论

0赞 BeastMaster64 1/6/2022
谢谢你指出来。
3赞 ferrouskid 1/6/2022 #2

我想这里可能有一点误会。当你最初这样做时,引用的对象是一个包含 1,2,3 的列表。这个列表被放在地图中。List<Integer> obj = Arrays.asList(1,2,3);obj

但是,当您这样做时,您将为引用分配一个新对象。obj = Arrays.asList(4,5,6);obj

请尝试以下操作:

public static void main(String[] args){
        List<Integer> obj = new ArrayList<>();
        obj.add(1);
        Map<Integer, List<Integer>> a = new HashMap<>();
        a.put(0, obj);
        a.get(0).forEach(System.out::println);
        obj.add(2);
        System.out.println();
        a.get(0).forEach(System.out::println);
    }

评论

0赞 BeastMaster64 1/6/2022
啊,我觉得自己很傻,我在脑海中替换了对象并保留了引用,忘记了地图复制了对对象的引用,谢谢你指出来。
1赞 ferrouskid 1/6/2022
别担心,我们都去过那里!我总是犯愚蠢的错误,真正对我有帮助的是一个不错的 IDE(我使用 intellij 用于 java,vscode 用于 python/js/ts)。祝你好运!