【问题标题】:Why does the augmented assignement operator in Java give a different result?为什么 Java 中的增广赋值运算符会给出不同的结果?
【发布时间】:2017-05-09 06:28:45
【问题描述】:

考虑以下代码:

class Converter {
    public static void main(String args[]) {
        byte num = 1;
        num = num * 2.5;
        System.out.println("Result is: " + num);
    }
}

编译器抛出以下错误:

error: incompatible types: possible lossy conversion from double to the byte at line 1

如果我更改main() 方法的第二行并使用*= 速记运算符:

class Converter {
    public static void main(String args[]) {
        byte num = 1;
        num *= 2.5;
        System.out.println("Result is: " + num);
    }
}

代码编译运行成功,输出如下:

Result is: 2

为什么*= 速记运算符与完整表达式num = num * 2.5 的行为不同?

【问题讨论】:

  • 为什么你认为它不会发生?它基本上是x = (byte)(x * y)。所以它确实有一个隐式类型转换。我的意思是第一个错误已经在警告您,类型转换将使您在从double 转换为byte 时失去精确度
  • 使用javap -v Converter.class 查看第二种情况发生了什么。特别注意 d2i 和 i2b 指令:)
  • 所以我可以说速记运算符抑制有损转换错误并简单地执行它的输入吗?
  • 没有。你不能。您可以说@SomeJavaGuy 所说的,实际上引用了 JLS,复合赋值(不是“速记”)运算符包括一个强制转换,一个您在非复合示例中省略的强制转换。

标签: java operators


【解决方案1】:

从 JLS compound assigment operator 文档中,您可以看到以下示例:

例如下面的代码是正确的:

short x = 3;
x += 4.6;

并导致 x 的值为 7,因为它等同于:

short x = 3;
x = (short)(x + 4.6);

默认情况下它只是自动转换结果。

PS : 在这个other answer 我试图解释你需要使用 JLS 进行如下操作的原因

short x = 3;
x = x + 1; //Won't compile

它真的很新,所以我愿意接受那里的建议。

【讨论】:

    【解决方案2】:

    根据java语言规范"15.26.2. Compound Assignment Operators"

    E1 op= E2 形式的复合赋值表达式是等价的 到 E1 = (T)((E1) op (E2)),其中 T 是 E1 的类型,除了 E1 只评估一次。

    您可以在编译后看到示例的字节码(检查instruction 3-10)。

       3: i2d //convert an int into a double
       4: ldc2_w          #2                  // double 2.5d
       7: dmul //multiply two doubles
       8: d2i //    convert a double to an int
       9: i2b //convert an int into a byte
      10: istore_1 //store int value into variable 1
    

    【讨论】:

    【解决方案3】:

    正如 AxelH 已经说过的那样,它是 compound assignement,但我想强调一下:

    E1 op= E2 形式的复合赋值表达式是等价的 到E1 = (T) ((E1) op (E2)),其中TE1的类型,除了E1 只评估一次。

    这意味着根据定义它正在转换结果。例如:

    byte b = 1;
    b *= 2.3;
    System.out.println(b); // prints 2
    

    来自您的评论:

    所以我可以说速记运算符抑制有损转换 错误并简单地执行它的输入?

    不,你不能。它没有抑制任何错误,因为在转换中没有错误(在这种情况下)。

    【讨论】:

    • @AxelH 我认为您的回答很好。我也投了赞成票。但我只是想强调为什么会这样。现在阅读 OP 的评论让我更好地解释它没有抑制任何错误。相反,它正在铸造。那是不同的。
    • 我同意,顺便说一下,您的示例应该使用b = 1 而不是b = 10 来显示有损转换;)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-11-04
    • 2012-09-27
    • 2011-11-20
    • 2012-06-09
    • 2022-01-21
    相关资源
    最近更新 更多