我们都知道在Java中这些运算符:
a++;
++a;
a += 1;
a = a + 1;
做同样的事情,他们只是在变量"a"上加1
然而,为什么这些说法并不都是真的,这背后的原则是什么?
byte a = 1;
a++;
++a;
a += 1;
a = a + 1; // This line will result to a compile time error
为什么?
无论何时在不同类型的两个操作数之间执行二进制运算,其中一个操作数都会升级为更高的类型。然后运算的结果就是这种类型的。
因此,在您的案例中,byte
类型a
首先被提升为int
,因为1
是int
类型。然后在加法运算之后,结果是类型为int
的。现在,由于不能将int
分配给byte
,因此需要进行类型转换以删除编译器错误:
byte a = 2;
a = a + 1; // Error: Cannot assign an int value to byte
a = (byte)(a + 1); // OK
现在,在复合赋值运算符的情况下,类型转换是隐式完成的。表达式:
a += 1
内部转换为:
a = (byte)(a + 1);
这在JLS-§15.26.2复合分配运算符:中有规定
形式E1-op=E2的复合赋值表达式等价于E1=(T)((E1)-op(E2)),其中T是E1的类型,不同之处在于E1仅被评估一次。
前缀增量运算符和后缀增量运算符的情况类似
根据JLS-§15.15一元算子:
前缀增量表达式的类型就是变量的类型。
a=a+1
这是由于表达式a = a + 1;
的类型。LHS被提升为CCD_ 10,然后进行加法运算。然后,您将尝试在不强制转换的情况下将int
值分配回byte
。
参考JLS 5.6.2
加宽基元转换(§5.1.2)适用于根据以下规则转换一个或两个操作数:
如果任一操作数的类型为double,则另一个操作数将转换为double。
否则,如果任一操作数的类型为float,则另一个操作数将转换为float。
否则,如果任一操作数的类型为long,则另一个操作数将转换为long。
否则,两个操作数都转换为int类型。
a++;++a
这里的类型就是变量的类型。再次按照JLS 15.15
前缀增量表达式的类型就是变量的类型。
前缀递减表达式的类型就是变量的类型。
a+=1
根据JLS 15.26.2
形式E1-op=E2的复合赋值表达式等价于E1=(T)((E1)-op(E2)),其中T是E1的类型,不同之处在于E1仅被评估一次。
因此,这里a += 1;
等价于a = (byte)(a+1);
,因为它是隐式完成的。