为什么 Java 的 + =,-=,* =,/ = 复合赋值运算符不需要强制转换?

直到今天,我还以为例如:

i += j;

只是以下方面的捷径:

i = i + j;

但是,如果我们尝试这样做:

int i = 5;
long j = 8;

那么i = i + j;不会编译,但是i += j;会编译的很好。

这是否意味着实际上i += j;是这样的快捷方式i = (type of i) (i + j)吗?

答案

与这些问题一样,JLS 保留了答案。在这种情况下,第1.5.26.2 节 “复合赋值运算符” 。摘录:

形式为E1 op= E2的复合赋值表达式等效于E1 = (T)((E1) op (E2)) ,其中TE1的类型,只是E1仅被评估一次。

§15.26.2 中引用的示例

[...] 以下代码正确:

short x = 3;
x += 4.6;

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

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

换句话说,您的假设是正确的。

这种转换的一个很好的例子是使用 * = 或 / =

byte b = 10;
b *= 5.7;
System.out.println(b); // prints 57

要么

byte b = 100;
b /= 2.5;
System.out.println(b); // prints 40

要么

char ch = '0';
ch *= 1.1;
System.out.println(ch); // prints '4'

要么

char ch = 'A';
ch *= 1.5;
System.out.println(ch); // prints 'a'

很好的问题。 Java 语言规范证实了您的建议。

例如,以下代码是正确的:

short x = 3;
x += 4.6;

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

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

是,

基本上当我们写

i += l;

编译器将此转换为

i = (int)(i + l);

我只是检查了.class文件代码。

真是一件好事

如果i = i + l则需要从long explicitlyint ,然后它将进行编译并提供正确的输出。喜欢

i = i + (int)l;

要么

i = (int)((long)i + l); // this is what happens in case of += , dont need (long) casting since upper casting is done implicitly.

但是在+=情况下,它就可以正常工作,因为运算符会隐式执行从右变量类型到左变量类型的类型转换,因此无需显式转换。

这里的问题涉及类型转换。

当您添加 int 和 long 时,

  1. 将 int 对象强制转换为 long,并且将两者都添加,就得到 long 对象。
  2. 但是长对象不能隐式转换为 int。因此,您必须明确地做到这一点。

但是+=的编码方式可以进行类型转换。 i=(int)(i+m)

在 Java 中,当可以将赋值操作右侧的表达式类型安全地提升为赋值左侧的变量类型时,将自动执行类型转换。因此,我们可以安全地分配:

byte -> short -> int -> long -> float -> double.

反之亦然。例如,我们不能自动将 long 转换为 int,因为第一个比第二个需要更多的存储空间,因此信息可能会丢失。要强制进行这种转换,我们必须进行显式转换。
类型 - 转换

有时,可以在面试中提出这样的问题。

例如,当您编写时:

int a = 2;
long b = 3;
a = a + b;

没有自动类型转换。在 C ++ 中,编译上面的代码不会有任何错误,但是在 Java 中,您会得到类似Incompatible type exception

因此,为了避免这种情况,您必须像这样编写代码:

int a = 2;
long b = 3;
a += b;// No compilation error or any exception due to the auto typecasting

主要区别在于,使用a = a + b ,不会进行类型转换,因此编译器会因为不进行类型转换而对您生气。但是, a += b ,实际上是将b类型转换为与a兼容的类型。所以如果你这样做

int a=5;
long b=10;
a+=b;
System.out.println(a);

您真正在做的是:

int a=5;
long b=10;
a=a+(int)b;
System.out.println(a);

这里的微妙之处...

j为双精度数且i为整数时, i+j有一个隐式类型转换。当它们之间存在运算时,Java 总是将整数转换为双精度

为了澄清i+=j ,其中i是整数, j是双精度数,可以描述为

i = <int>(<double>i + j)

请参阅: 此隐式转换描述

为了清楚起见,您可能希望在这种情况下将j强制转换为(int)