39

如果我创建一个新的 HashMap 和一个新的 List,然后使用任意键将 List 放在 Hashmap 中,然后再调用List.clear()它会影响我在 HashMap 中放置的内容吗?

这里更深层次的问题是:当我向 HashMap 添加内容时,是复制并放置了新对象还是放置了对原始对象的引用?

谢谢!

4

8 回答 8

48

这里发生的事情是您将指向哈希图中的列表的指针,而不是列表本身。

当你定义

List<SomeType> list;

您正在定义指向列表的指针,而不是列表本身。

当你这样做

map.put(somekey, list);

您只是存储指针的副本,而不是列表。

如果在其他地方,您跟随该指针并在其末尾修改对象,则持有该指针的任何人仍将引用相同的修改对象。

有关 Java 中传递值的详细信息,请参阅http://javadude.com/articles/passbyvalue.htm 。

于 2009-06-01T13:39:32.177 回答
12

Java 是按值传递引用。

将列表添加到哈希映射只是添加对哈希映射的引用,它指向同一个列表。因此,直接清除列表确实会清除您在哈希图中引用的列表。

于 2009-06-01T13:18:02.563 回答
5

当我向 HashMap 添加内容时,是复制并放置了新对象还是放置了对原始对象的引用?

它始终是对对象的引用。如果您清除 HashMap,该对象仍将是“活动的”。如果没有人再引用它,那么该对象将被垃圾收集器销毁。如果您需要复制它,请查看 Object.clone() 方法和 Cloneable 接口

于 2009-06-01T14:26:42.177 回答
4
Map<Integer, Integer> hasmapA = new HashMap<>();
hasmapA.put("key1", "value1");
hasmapA.put("key2", "value2");
hasmapA.put("key3", "value3");
  1. 按引用复制:如果将一个HashMap分配给另一个,则两者都指向内存中的相同引用。

    地图 hasmapB;

    hashmapB = hashmapA;

如果您对其中任何一个进行更改,更改将反映在两个HashMap中,因为两者都引用相同的位置。

  1. 按值复制:如果你想

克隆/深拷贝/创建单独的内存位置/创建单独的对象

复制 hashmapA 的内容时 hashmapB 的

Map<Integer, Integer> hashmapB = new HashMap<>();;

hashmapB.putAll(hashmapA)

注意:** 您是否注意到 hashmapB 声明的两点不同?在第二点我们必须调用 **HashMap构造函数。这样我们就可以把hashmapA的所有数据放到hashmapB中。

参考

于 2015-06-16T05:18:43.820 回答
1

通常,您总是在 Java 中处理引用(除非您自己使用“new”[1] 显式创建一个新对象)。

因此,它是一个参考,而不是您存储在地图中的完整对象副本,更改列表也会影响您在浏览地图时看到的内容。

这是一个功能,而不是一个错误:)

[1] 清教徒将包括“clone()”和序列化,但对于大多数 java 代码,“new”是获取对象的方式。

于 2009-06-01T14:26:43.220 回答
1

试试看

包 test32;

导入 java.util.ArrayList;
导入 java.util.HashMap;
导入 java.util.List;

类Foo {
    公共 Foo(int id,字符串名称){
 这个.id=id;
 这个名字=名字;
    }

    公共静态无效主要(字符串[]参数){
 HashMap strs = new HashMap();

 // 创建一个对象列表
 列表 ls = new ArrayList();
 ls.add(new Foo(1, "Stavros"));
 ls.add(new Foo(2, "Makis"));
 ls.add(new Foo(3, "Teo"));
 ls.add(new Foo(4, "Jim"));

 // 将对象的引用从列表复制到 hashmap
 strs.put("1", ls.get(0));
 strs.put("2", ls.get(1));
 strs.put("3", ls.get(2));
 strs.put("4", ls.get(3));

 System.out.println("修改前的列表:" + ls);
 System.out.println("变更前的地图:" + strs);
 // 从 hashmap 中获取一个对象
 Foo f=strs.get("1");
 // 设置不同的值
 f.setId(5);
 // 观察差异反映到列表和哈希图也
 System.out.println("修改后的列表:"+ls);
 System.out.println("修改后的地图:"+strs);
    }

    私人 int id;
    公共无效setId(int id){
 这个.id=id;
    }
    公共 int getId() {
 返回这个.id;
    }

    私有字符串名称;
    公共无效集合名称(字符串名称){
 这个名字=名字;
    }
    公共字符串 getName() {
 返回这个名称;
    }

    公共字符串 toString() {
 StringBuilder sb = new StringBuilder();
 sb.append(id);
 sb.append("-");
 sb.append(name);
 返回 sb.toString();
    }
}
于 2010-04-28T09:45:24.967 回答
1

正确答案解释如下:假设您有一个名为 hashmap 的 HashMap,并且最初您在此 HashMap 中放置了一个键值对,例如 hashmap<"test1","test2">。在此之后,当您将此哈希图传递给一个函数,在该函数中您再次将其值更改为 test3,例如 hashmap.put("test1", "test3") 并在 main 方法中再次打印该映射,Java Pass by Value Concept 在这里失败。

原因是:当您使用 HashMap 时,它会对 Key(test1) 进行哈希处理并存储值。当您将它传递给再次更改其值的函数时,它再次对同一键进行哈希处理并获取相同的内存地址并相应地更改值。这就是为什么当您尝试检索密钥“test1”时,它会为您提供“test3”的结果

于 2013-07-15T16:44:40.520 回答
-2

天哪,Java 中的一切都是按价值传递的。当你传递一个对象时,你传递的值就是对象引用。具体来说,您正在传递对象引用的副本。Java 中也没有指针,尽管引用是相似的。修正它!

于 2009-06-01T13:53:32.930 回答