一个老话题,short s=s+1的日常
最近又要重新捡起java了,因为没做过开发的it人生是不完整的,so,就从一个万年老梗 short s=s+1为何编译失败开始新的开始吧。
calss test
{
public static void main(string[] args)
{
short s=1;
s=s+1;
s+=1;
s++;
system.out.println(s);
}
}
对于这段代码,编译肯定无法通过的,原因是什么?原因就是s=s+1会出错,这是很久之前很常见的一个面试题,这么多年过去了,解答的套路都固定了,让我们看看j从ava的创造者视角看这个问题是怎么样的?引用资料java语言规范(JLS)
1.JLS(中文版第三版)5.2 赋值转换
1)当把表达式的值赋予一个变量时,就会发生赋值转换:必须把表达式的类型转换为变量的类型;
2)如果表达式是类型byte,short,char,int的常量表达式,则如果变量类型是byte,short,char,并且常量表达式的值在变量的类型中是可以表示的,那么就执行窄化转换 (narrowing conversion),如果不能通过赋值环境中允许的转换把表达式的类型转换成变量的类型,那么编译时会报错。这个可以用来解释s=1,为何将int赋值给short不会报错。
3)s=s+1为什么会报错?这里我没有看JLS,因为s=s+1,左边有变量参与,编译器在无法分析出该变量的值是什么,因为s为变量,其值不确定无法确定s+1是否超出short范围,为了防止进行类型转换时丢失精度,所以编译器直接当成无法确定来处理,报错了事。so,当有变量为byte,short,char时,编译器就是这么干的。需要知道的是在编译期间,虚拟机只做语法检查,而不会进行计算动作,也就是说虚拟机不会对s+1是否查出s的范围而进行一次计算判断。
4)s++呢?对于后缀++,JLS说在s+1时也要执行二元数值提升,即一个操作数是double,那么把另一个操作数转化成double;否则一个操作数是float,那么把另一个操作数转化成float;否则一个操作数是long,那么把另一个操作数转化成long;否则两个都转化为int(JLS中文三版5.6.2);如有必要将s+1的和进行窄化转换,即将s+1做强制转换(short)(s+1)然后赋给s。(JLS中文三版15.15.1)
5)最后s+=1,JLS中文三版15.26.2说对于组合运算符形如E1 op=E2的组合赋值表达式等价于E1=(T)((E1)op(E2))其中T为E1的类型,例如s+=1等价于s=(short)(s+1)。
PS:PLS的原版和翻译版
A unary expression preceded by a ++ operator is a prefix increment expression.
The result of the unary expression must be a variable of a type that is convertible
(§5.1.8) to a numeric type, or a compile-time error occurs. The type of the prefix
increment expression is the type of the variable. The result of the prefix increment
expression is not a variable, but a value.
At run time, if evaluation of the operand expression completes abruptly, then
the prefix increment expression completes abruptly for the same reason and no
incrementation occurs. Otherwise, the value 1 is added to the value of the variable
and the sum is stored back into the variable. Before the addition, binary numeric
promotion (§5.6.2) is performed on the value 1 and the value of the variable. If
necessary, the sum is narrowed by a narrowing primitive conversion (§5.1.3) and/
or subjected to boxing conversion (§5.1.7) to the type of the variable before it is
stored. The value of the prefix increment expression is the value of the variable
after the new value is stored.
Note that the binary numeric promotion mentioned above may include unboxing conversion (§5.1.8) and value set conversion (§5.1.13). If necessary, value set
conversion is applied to the sum prior to its being stored in the variable.
A variable that is declared final cannot be incremented (unless it is a definitely unassigned (§16) blank final variable (§4.12.4)), because when an access of
such a final variable is used as an expression, the result is a value, not a variable.
Thus, it cannot be used as the operand of a prefix increment operator.
对于第一段话有些不明白,在论坛上问了也比较模糊:点击打开链接