为什么Java中的增广赋值运算符会给出不同的结果?
考虑以下代码:为什么Java中的增广赋值运算符会给出不同的结果?,java,operators,Java,Operators,考虑以下代码: 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 doubl
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
为什么*=
速记运算符的行为不同于JLS文档中的完整表达式num=num*2.5
?,您可以看到以下示例:
例如,以下代码是正确的:
结果x的值为7,因为它等于:
默认情况下,它只是自动转换结果
PS:在本文中,我试图解释您需要使用JLS强制执行以下操作的原因
short x = 3;
x = x + 1; //Won't compile
它确实是新的,所以我愿意接受这里的建议。正如AxelH已经说过的,它是一个新的,但我想用uderline表示: 形式为
E1 op=E2
的复合赋值表达式是等效的
toE1=(T)((E1)op(E2))
,其中T
是E1
的类型,除了E1
仅评估一次
这意味着,根据定义,它正在铸造结果。例如:
byte b = 1;
b *= 2.3;
System.out.println(b); // prints 2
来自您的评论:
那么我可以说速记操作符抑制了有损转换吗
错误并简单地执行它的输入
不,你不能。它不会抑制任何错误,因为在强制转换(在此上下文中)中没有错误。根据java语言规范 形式为E1 op=E2的复合赋值表达式是等效的 to E1=(T)((E1)op(E2)),其中T是E1的类型,但E1除外 仅评估一次 在编译之后,您可以看到示例的字节码(检查3-10)
为什么你认为这不会发生?它基本上执行
x=(字节)(x*y)
。所以它确实有一个隐式类型转换。我的意思是,第一个错误已经警告您,当从double
转换为byte
时,类型转换将使您失去预精度。请使用javap-v Converter.class
查看第二种情况下发生了什么。请特别注意d2i和i2b指令:)那么我可以说速记操作符抑制有损转换错误,只做它的输入吗?不,你不能。你可以说@SomeJavaGuy所说的,实际上引用了JLS,复合赋值(不是“速记”)操作符包括一个cast,一个在非复合示例中省略的cast。@AxelH我认为你的答案是好的。我也投了赞成票。但我只是想强调为什么会发生这种情况。现在读到OP的评论让我更好地解释,它并没有抑制任何错误。相反,它是铸造。这是不同的。我同意,顺便说一下,您的示例应该使用b=1
而不是b=10
来显示有损转换;)
short x = 3;
x = x + 1; //Won't compile
byte b = 1;
b *= 2.3;
System.out.println(b); // prints 2
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