【问题标题】:Assigning a variable during arithmetic in Java?在Java算术期间分配变量?
【发布时间】:2022-10-12 22:14:30
【问题描述】:

我的教授在一次讲座中给了我们这个 java sn-p,我不明白为什么它输出 12。

int b = 9; 
b = b + (b = 3); 
System.out.println( "b = " + b );

我的想法是,由于括号赋予操作优先级,b 将首先重新分配给 3。然后,它将转到b = 3 + 3 = 6。显然,情况并非如此,b = 9 + 3 = 12 实际上已被执行。为什么代码从左到右执行而不是先执行括号?

对不起,我的标题很糟糕,我不知道该怎么称呼它,因为我认为您实际上从未以这种方式编程。

【问题讨论】:

    标签: java integer-arithmetic java-17


    【解决方案1】:

    在更改 b 的值之前评估右侧的整个表达式。此外,它是从左到右评估的。所以b 的值在表达式的计算过程中确实发生了变化,但是在第二个术语将b 设置为3 之前,第一个b 已经被采样为9b 无关紧要最终被设置为表达式的结果。术语(b = 3) 具有值3。所以任务就是:

    b = 9 + 3
    

    所以你得到的结果是12

    另一方面,声明:

    b = (b = 3) + b;
    

    简化为

    b = 3 + 3
    

    导致6。发生这种情况的原因再次是,表达式是从左到右计算的。所以第一项的值为3,并且在第二项b 被计算之前将b 设置为3,因此值为3

    【讨论】:

    • 但是为什么在 b 的值改变之前计算右手边呢?括号是否意味着首先执行 b=3,这也应该改变第一个 b 的值?如果我也有 a=3 并且 b = b * (b + a),则 (b+a) 在 b 与另一个值相乘之前执行。
    • 是的你是对的。我只是为你澄清了这一切。评估的顺序在这里有很大的不同。
    • @S.King 在这种情况下,括号不会改变优先级。对于a * (b + c),括号确保它不会被解释为(a * b) + c。但是,对于a + (b = c),没有其他解释,因为(a + b) = c 根本不起作用。首先需要括号以使在另一个表达式中嵌入赋值在语法上有效,而不是改变运算符的优先级。
    【解决方案2】:

    优先并不意味着它运行第一的.它只是让您重新连接运算符优先级。通常像1 + 2 * 3 这样的东西被解析为:

    • A 和 B 之间的加法运算,其中
    • A 是整数文字 '1'
    • B 是表达式2 * 3

    为什么?因为运算符优先级规则规定 * 绑定比 + 更紧密。使用括号,您可以覆盖它; (1 + 2) * 3 是 A 和 B 之间的乘法运算,其中 B 是“3”字面量,A 是“1 + 2”。这就是它所做的一切。它不会改变解决问题的顺序。

    Java首先计算'b'(它是9),然后它计算(b = 3)(它是3,并且作为副作用,使b变为3),因此该表达式是12,然后将其分配给b,所以是12。

    为什么它首先评估+ 的左侧?因为规范是这样说的:从左到右解析。

    试试这个有趣的:

    int b = 9;
    b = (b = 3) + b;
    System.out.println(b);
    

    现在它按预期打印 6 。

    【讨论】:

      【解决方案3】:

      这是与机器语言相关的解释。

      CPU 通常不知道变量和运算符优先级。它们有一些可用于操作的寄存器,以及用于存储超出其寄存器容量的数据的存储单元。内存单元有编号,当我们写variable b 时,编译器会将其转换为某个内存单元的编号——地址。存储在该地址处的值是变量 b 的值。

      但请记住,变量并没有被计算——所有这些都发生在寄存器中。因此,要将两个数字相加,必须先将它们加载到 CPU 寄存器中。

      int b = 9;
      

      所以在上面的指令中,代表 b 的存储单元被加载了值 9。

      b = b + (b=3)
      

      在这条指令中,b 将被复制到一个寄存器(可能是累加器,通常称为寄存器 A)中,以添加 (b=3)。现在值 3 在寄存器没有改变的情况下被加载到内存单元中,最后将值 3 添加到仍然在寄存器中的值:b 的旧值。

      因此操作导致

      b = 9 + 3
      

      你有12个。

      实际上,加载寄存器的时间可能会有所不同,因为分配可能是需要将寄存器重用于其他内容的子路由。但是,为了避免副作用,必须恢复寄存器以使编程逻辑保持不变。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-12-21
        • 2020-08-14
        • 2023-03-23
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多