x = x*0.90; 给出有损转换错误。x*=0.90;才不是。为什么?

ppr*_*rav 25 java double integer multiplication assignment-operator

我已经写了代码:

int x = 18;
x *= 0.90; 
System.out.println(x);
Run Code Online (Sandbox Code Playgroud)

这段代码打印出来16

然而,当我写下

int x = 18;
x = x * 0.90; 
System.out.println(x);
Run Code Online (Sandbox Code Playgroud)

它给了我以下错误:incompatible types: possible lossy conversion from double to int

我预计这两个代码示例都会导致与 相同的错误x *= y;x = x * y;x *= 0.90;不知何故有效,但x = x * 0.90;无效。为什么会这样呢?

rzw*_*oot 30

因为 Java 语言规范 (JLS) 是这么说的。这有点奇怪,但是,当使用复合赋值运算符(*=+=等)时,强制转换是隐含的。

\n

请参阅JLS \xc2\xa715.26.2,它清楚地显示了该部分顶部示例中的演员表。

\n

为什么要这样做?好吧,我认为 SO 不是询问“30 年前编写 JLS 规范的这一部分时设计师在想什么”的合适地方。

\n

编辑:这个答案曾经提到“可能是因为 C”,但正如评论所示,不,在 C 中,两种形式都不需要显式转换。

\n

  • 我想,他们认为在“... *= ...”的情况下坚持显式强制转换是不切实际的,因为,语法会是什么样子?请注意,这同样适用于“++”和“--”运算符。 (9认同)
  • 我认为你不能将这种差异归咎于 C。从历史上看,C 对类型转换非常宽容,具有广泛的算术运算类型转换规则。也就是说,在这种情况下,C 对于标准乘法或复合运算都不会产生错误。两个值都会(默默地)提升为浮点数以进行乘法,然后在放回到变量中时分解为整数。-- Java 对 `*` 有错误,但对 `*=` 没有错误,这一事实完全是 Java 创建者的责任,与 Thompson & Ritchie 无关。(PS Ritchie 十多年前去世了。) (4认同)
  • *“为什么要这样做?嗯,我不认为 SO 是问‘30 年前编写 JLS 规范的这一部分时设计师在想什么’的合适地方。”* << 如果 StackOverflow 真的这么做的话对于这个问题来说是一个不好的地方,我认为这对于 https://langdev.stackexchange.com/ 来说是一个很好的问题。请注意,Java 并不是唯一一种“a = a * b;”和“a *= b;”不完全同义词,或者“a += b;”和“a += b;”不完全同义词的语言。例如,在 python3 中,如果“a”是可变类型(例如“list”),则“a += b”和“a = a + b”总是不同的。 (3认同)

sup*_*cat 10

Java 的设计者通常更看重一致性,而不是特定情况的敏感性。给定byte a,b; int i;,表达式a & b将通过将操作数转换为 来计算int,并因此产生结果类型int。因此,没有一种好的方法可以要求对 进行强制转换,a = (byte)i;但又不需要对 进行强制转换a = (byte)(a & b);。如果表达式写为,则在执行赋值之前a &= b;将无法转换运算符的结果。&Java并没有让&=(和其他复合赋值)运算符对byteshortchar毫无用处,而是选择在组合运算符的结果与赋值结果的使用之间进行隐式转换。