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型也会出现这样的情况。
书中观点:
- 对于Java使用者是:不要将byte/char/short用于复合运算符出现的场景。
- 对于Java语言设计者:窄化转型不能silently地进行,更进一步,是否允许byte/char/short参与复合运算符出现的场景也值得讨论。
我赞同第一条,对第二条持保留意见。
附
- JLS 5.1.3 Narrowing Primitive Conversions
- JLS 15.26.2 Compound Assignment Operators