添加字节时的不同编译器行为

Zoh*_*aib 5 java

byte b1 = 3;
byte b2 = 0;

b2 = (byte) (b2 + b1);  // line 3
System.out.println(b2);

b2 = 0;
b2 += b1;               // line 6
System.out.println(b2);
Run Code Online (Sandbox Code Playgroud)

在第3行,如果我们不将结果类型转换为字节,那么这是一个编译错误 - 这可能是因为加法的结果总是int而int不适合一个字节.但显然我们不必在第6行进行类型转换.这两个语句,第3行和第6行都不等同吗?如果不是那么还有什么不同?

Jon*_*eet 10

是的,这两行是等价的 - 但它们使用了语言的不同部分,并且它们被JLS的不同部分所覆盖.第3行是普通的+运算符,应用于已提升为的字节int,给出int结果.必须先进行转换才能将其分配回byte变量.

第6行是一个复合赋值运算符,如JLS第15.26.2节所述:

在运行时,表达式以两种方式之一进行评估.如果左侧操作数表达式不是数组访问表达式,则需要四个步骤:

  • 首先,评估左侧操作数以产生变量.如果此评估突然完成,则赋值表达式出于同样的原因突然完成; 不评估右侧操作数,也不进行赋值.
  • 否则,保存左侧操作数的值,然后评估右侧操作数.如果此评估突然完成,则赋值表达式会出于同样的原因突然完成,并且不会发生任何分配.
  • 否则,左侧变量的保存值和右侧操作数的值用于执行复合赋值运算符指示的二元运算.如果此操作突然完成,则赋值表达式会因同样的原因突然完成,并且不会发生任何赋值.
  • 否则,二进制操作的结果将转换为左侧变量的类型,经过值集转换(第5.113节)到相应的标准值集(不是扩展指数值集),结果转换的内容存储在变量中.

这是使其与众不同的最后一部分(如突出显示的那样).

事实上,该部分的开头显示了等价:

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

  • 感谢Jon Skeet回答我的第一个问题:) (2认同)