使用 put() 与 putAll() 时导致无限循环的原因
What causes an Infinite loop when using put() vs putAll()
在下面的简单示例代码中,我想快速将 HashMap 'additional' 放入 Process 对象的有效负载中。但是,我注意到当我使用 .put() 以便将数据更深地嵌套在附加键值(“exampleData”)后面时,会发生无限循环:
public class Process {
public Map<String, Object> getPayload() {
return payload;
}
public void setPayload(Map<String, Object> payload) {
this.payload = payload;
}
Map<String, Object> payload;
}
public static void main(String[] args) {
Process process = new Process();
LinkedHashMap<String, Object> linkedHashMap = new LinkedHashMap<>();
linkedHashMap.put("uuid", "uuid");
process.setPayload(linkedHashMap);
Map<String, Object> additional = new HashMap<>();
additional.putAll(process.getPayload()); //additional.put("exampleData", process.getPayload());
process.getPayload().put("additionalData",additional);
}
当使用 putAll() 执行代码时,不会发生无限循环,Process 对象如下所示:
但是,当使用 put() 而不是 putAll() 时,会发生无限循环,有效负载包含自身并发生 WhosebugError:
是什么导致了这个无限循环?为什么 putAll() 不受此影响?
行后:
additional.put("exampleData", process.getPayload());
additional
现在有对进程负载的引用。相关对象图如下所示:
process ---> payload <---- additional
(箭头代表参考文献)
然后你做到了:
process.getPayload().put("additionalData",additional);
这会添加到负载中,一个指向 additional
的新引用。注意这是如何创建一个循环的:
process ---> payload <---- additional
| ^
|_______________|
这很好,直到您尝试打印 payload
的内容。它的值之一是additional
所以additional
的内容也需要打印,additional
的值之一是payload
,所以payload的内容被打印再次,循环继续......不幸的是,为 Map
编写 toString
方法的人没有写任何东西来检测这个。
putAll
另一方面,
Copies all of the mappings from the specified map to this map.
因此,additional.putAll(process.getPayload());
不会使 additional
引用 payload
。相反,它只是将有效载荷具有的任何键和值添加到 additional
.
此外,如果您创建一个包含有效负载的所有键和值的新映射,并使用 put
.[=35 将其添加到 additional
,它也不会创建循环=]
additional.put("exampleData", new HashMap<>(process.getPayload()));
而不是引用 payload
,另外将引用新地图:
process ---> payload additional ----> a copy of payload
| ^
|_______________|
在下面的简单示例代码中,我想快速将 HashMap 'additional' 放入 Process 对象的有效负载中。但是,我注意到当我使用 .put() 以便将数据更深地嵌套在附加键值(“exampleData”)后面时,会发生无限循环:
public class Process {
public Map<String, Object> getPayload() {
return payload;
}
public void setPayload(Map<String, Object> payload) {
this.payload = payload;
}
Map<String, Object> payload;
}
public static void main(String[] args) {
Process process = new Process();
LinkedHashMap<String, Object> linkedHashMap = new LinkedHashMap<>();
linkedHashMap.put("uuid", "uuid");
process.setPayload(linkedHashMap);
Map<String, Object> additional = new HashMap<>();
additional.putAll(process.getPayload()); //additional.put("exampleData", process.getPayload());
process.getPayload().put("additionalData",additional);
}
当使用 putAll() 执行代码时,不会发生无限循环,Process 对象如下所示:
但是,当使用 put() 而不是 putAll() 时,会发生无限循环,有效负载包含自身并发生 WhosebugError:
是什么导致了这个无限循环?为什么 putAll() 不受此影响?
行后:
additional.put("exampleData", process.getPayload());
additional
现在有对进程负载的引用。相关对象图如下所示:
process ---> payload <---- additional
(箭头代表参考文献)
然后你做到了:
process.getPayload().put("additionalData",additional);
这会添加到负载中,一个指向 additional
的新引用。注意这是如何创建一个循环的:
process ---> payload <---- additional
| ^
|_______________|
这很好,直到您尝试打印 payload
的内容。它的值之一是additional
所以additional
的内容也需要打印,additional
的值之一是payload
,所以payload的内容被打印再次,循环继续......不幸的是,为 Map
编写 toString
方法的人没有写任何东西来检测这个。
putAll
另一方面,
Copies all of the mappings from the specified map to this map.
因此,additional.putAll(process.getPayload());
不会使 additional
引用 payload
。相反,它只是将有效载荷具有的任何键和值添加到 additional
.
此外,如果您创建一个包含有效负载的所有键和值的新映射,并使用 put
.[=35 将其添加到 additional
,它也不会创建循环=]
additional.put("exampleData", new HashMap<>(process.getPayload()));
而不是引用 payload
,另外将引用新地图:
process ---> payload additional ----> a copy of payload
| ^
|_______________|