【问题标题】:Local variable value changing after passing it to method将局部变量值传递给方法后发生变化
【发布时间】:2019-10-29 16:24:54
【问题描述】:

我正在使用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
        }
      }
    }
  }
}

为什么会这样?我认为对“子节点”的任何更改都不应该反映在“jsonNode”上。是不是我的理解有误?

【问题讨论】:

  • 我更新了关于您评论的答案。

标签: java json pass-by-reference pass-by-value jsonnode


【解决方案1】:

这里:

jsonNode = mapper.readTree(deviceShadow);

这会为您的 JSON 数据创建一个内存表示。只是某种反映 JSON 字符串的 结构 和内容的数据结构。

这里是:

JsonNode subNode = jsonNode.get(...

然后遍历该内存结构并识别它的子结构。然后你修改那个子结构:

node.put("solenoid", 100);

毫不奇怪:当您修改内存中的数据结构时,您也修改了您的数据!

换句话说:你的假设是完全错误的。想象一下,你有一些标准的 Java Tree 实现,它有一堆节点。现在您在该树中识别一个特定的 Node 对象,并更改该 Node 的值。当然,这也会改变 Tree 的内容,因为 Node 位于 inside 那棵 Tree!

长话短说:您将数据读入内存,您专门针对该数据的某个部分,您更改数据,数据就更改了。这就是全部!

仅作记录:最后,我们讨论的是底层 JSON 库的语义。您在这里使用的库......当您请求子节点时,根本不会复制或克隆数据。它只是给你一个直接进入数据的“指针”。其他库可能会以不同的方式执行此操作,例如,可以想象所有数据都是只读的,并且通过返回一个全新的 Node 对象来完成修改,与初始数据分离。

为了不改变初始 jsonNode 对象,唯一的选择似乎是解析你的数据两次。因此,通过两次处理您的输入来创建完全独立的 JsonNode。这当然会使您的代码所做的工作量翻倍。

【讨论】:

  • 感谢@GhostCat!有没有办法改变“subNode”值而不反映“jsonNode”?我尝试在操作之前将“jsonNode”的值复制到另一个 JsonNode 对象中,但更改也反映在 那个 新对象中。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-12-07
  • 1970-01-01
  • 2014-05-14
  • 2013-04-20
  • 2011-09-10
  • 2016-07-20
相关资源
最近更新 更多