IT Notes‎ > ‎Java‎ > ‎Java Language‎ > ‎《Java 解惑》笔记‎ > ‎

Puzzle 31: Ghost of Looper

复合赋值运算的返回类型

复合赋值符可能导致narrowing primitive conversions,因为按照JLS 15.26.2的定义:
  • A compound assignment expression of the form E1 op= E2 is equivalent to E1 = (T)((E1) op (E2)), where T is the type of E1, except that E1 is evaluated only once. 
所以对于下面这段代码:
i = -1
while ( i != 0) {
        i >>>= 1;
}
当i为short,int型的情况是不同的。一个一个分析:

1. i为short型


代码片段可以依据复合运算的定义还原为
short i = -1;
while (i != 0) {
            i = (short) (i >>> 1);
}
执行的时候,由于位移操作要求对不是int/long型的整数转型成为int/long型再进行运算,所以i首先宽转型为int,从0xffff变成0xffffffff,然后作无符号右移,成为0x7fffffff,再窄转型为short的0xffff,它不等于0,所以循环继续,以下过程和第一次循环一样。这个循环不会终止。

除了short型,i为byte型也会出现这样的情况。

char无法声明 char i = -1;只能写成 char i = (char) -1;输出结果类似于i为int型时。

2. i为int型

代码片段可以依据复合运算的定义还原为
int i = -1;
while (i != 0) {
            i = i >>> 1;
}
执行的时候,没有强制转型了,都是int范围内,i从0xffffffff变成0x7fffffff,不等于0,继续,变成0x3fffffff,如此,最后变成0,终止循环。

除了int型,long型也会出现这样的情况。


书中观点:
  1. 对于Java使用者是:不要将byte/char/short用于复合运算符出现的场景。
  2. 对于Java语言设计者:窄化转型不能silently地进行,更进一步,是否允许byte/char/short参与复合运算符出现的场景也值得讨论。
我赞同第一条,对第二条持保留意见。



  1. JLS 5.1.3 Narrowing Primitive Conversions
  2. JLS 15.26.2 Compound Assignment Operators
Comments