将局部变量值传递给方法后更改
Local variable value changing after passing it to method
我正在使用 com.fasterxml.jackson.databind.JsonNode
java 库来解析 JSON
并对 JSON
字符串执行如下操作 -
public static void main(String[] args) {
{
String jsonString = "{\"state\":{\"reported\":{\"deviceParams\":{\"deviceStatus\":{\"solenoid\":10,\"airFlow\":20}}}}}";
ObjectMapper mapper = new ObjectMapper();
JsonNode jsonNode = null;
try {
jsonNode = mapper.readTree(jsonString);
} catch (IOException e) {
e.printStackTrace();
}
JsonNode subNode = jsonNode.get("state").get("reported").get("deviceParams").get("deviceStatus");
//Now subNode = {"solenoid":10,"airFlow":20}
modifySubNode((ObjectNode) subNode);
//type-casting JsonNode to ObjectNode since JSON manipulation like deletion and addition of nodes is only allowed in ObjectNode, not JsonNode
}
private static void modifySubNode(ObjectNode node) {
if (node.get("solenoid") != null) {
node.put("solenoid", 100);
}
}
函数调用 modifySubNode()
后,我希望 jsonNode
的值保持为
{
"state":
{
"reported":
{
"deviceParams":
{
"deviceStatus":
{
"solenoid": 10,
"airFlow": 20
}
}
}
}
}
但是,它变成了这个
{
"state":
{
"reported":
{
"deviceParams":
{
"deviceStatus":
{
"solenoid": 100,
"airFlow": 20
}
}
}
}
}
为什么会这样?我认为对 "subNode" 的任何更改都不应该反映在“jsonNode
”上。是不是我理解有误?
这里:
jsonNode = mapper.readTree(deviceShadow);
这会在 内存中 表示您的 JSON 数据。只是反映 结构 和 JSON 字符串内容的某种数据结构。
这里是:
JsonNode subNode = jsonNode.get(...
然后遍历 in-memory 结构并识别其中的一个 sub-structure。然后你修改 that 子结构:
node.put("solenoid", 100);
毫不奇怪:当您修改 in-memory 数据结构时,您也修改了您的数据!
换句话说:你的假设是完全错误的。假设您有一些标准的 Java 树实现,其中有一堆节点。现在您在该树中标识一个特定的 Node 对象,并更改该 Node 的值。当然,这也会更改树的内容,因为该节点位于 inside 该树!
长话短说:你把数据读到内存里,你专门针对那个数据的某一部分,你改数据,数据就改了。仅此而已!
谨记:最后,我们讨论的是底层 JSON 库的语义。您在此处使用的库...在您请求子节点时根本不会复制或克隆数据。它只是让您 "pointer" 直接进入数据。其他库可能会以不同的方式执行此操作,例如可以想象所有数据都是只读的,并且修改是通过返回一个全新的 Node 对象来完成的,与初始数据分离。
为了不改变初始的 jsonNode 对象,唯一的选择似乎是解析你的数据 两次。因此,通过两次处理您的输入来创建完全独立的 JsonNode。这当然会使您的代码所做的工作量加倍。
我正在使用 com.fasterxml.jackson.databind.JsonNode
java 库来解析 JSON
并对 JSON
字符串执行如下操作 -
public static void main(String[] args) {
{
String jsonString = "{\"state\":{\"reported\":{\"deviceParams\":{\"deviceStatus\":{\"solenoid\":10,\"airFlow\":20}}}}}";
ObjectMapper mapper = new ObjectMapper();
JsonNode jsonNode = null;
try {
jsonNode = mapper.readTree(jsonString);
} catch (IOException e) {
e.printStackTrace();
}
JsonNode subNode = jsonNode.get("state").get("reported").get("deviceParams").get("deviceStatus");
//Now subNode = {"solenoid":10,"airFlow":20}
modifySubNode((ObjectNode) subNode);
//type-casting JsonNode to ObjectNode since JSON manipulation like deletion and addition of nodes is only allowed in ObjectNode, not JsonNode
}
private static void modifySubNode(ObjectNode node) {
if (node.get("solenoid") != null) {
node.put("solenoid", 100);
}
}
函数调用 modifySubNode()
后,我希望 jsonNode
的值保持为
{
"state":
{
"reported":
{
"deviceParams":
{
"deviceStatus":
{
"solenoid": 10,
"airFlow": 20
}
}
}
}
}
但是,它变成了这个
{
"state":
{
"reported":
{
"deviceParams":
{
"deviceStatus":
{
"solenoid": 100,
"airFlow": 20
}
}
}
}
}
为什么会这样?我认为对 "subNode" 的任何更改都不应该反映在“jsonNode
”上。是不是我理解有误?
这里:
jsonNode = mapper.readTree(deviceShadow);
这会在 内存中 表示您的 JSON 数据。只是反映 结构 和 JSON 字符串内容的某种数据结构。
这里是:
JsonNode subNode = jsonNode.get(...
然后遍历 in-memory 结构并识别其中的一个 sub-structure。然后你修改 that 子结构:
node.put("solenoid", 100);
毫不奇怪:当您修改 in-memory 数据结构时,您也修改了您的数据!
换句话说:你的假设是完全错误的。假设您有一些标准的 Java 树实现,其中有一堆节点。现在您在该树中标识一个特定的 Node 对象,并更改该 Node 的值。当然,这也会更改树的内容,因为该节点位于 inside 该树!
长话短说:你把数据读到内存里,你专门针对那个数据的某一部分,你改数据,数据就改了。仅此而已!
谨记:最后,我们讨论的是底层 JSON 库的语义。您在此处使用的库...在您请求子节点时根本不会复制或克隆数据。它只是让您 "pointer" 直接进入数据。其他库可能会以不同的方式执行此操作,例如可以想象所有数据都是只读的,并且修改是通过返回一个全新的 Node 对象来完成的,与初始数据分离。
为了不改变初始的 jsonNode 对象,唯一的选择似乎是解析你的数据 两次。因此,通过两次处理您的输入来创建完全独立的 JsonNode。这当然会使您的代码所做的工作量加倍。