一、以容量角度来解释:
对两个容量不一样的数据类型的变量进行算术运算时,java会自动将小容量的变量进行精度提升,然后再进行运算,得到的结果类型是提升后的大容量的数据类型.如果将该结果赋值给小容量的数据类型的变量,则必须进行强制的类型转换,否则编译程序会报损失精度错.
short s1 = 1;
int i = 1;
首先,因为short类型是16位的,而int类型是32位的,在进行
(s1+i) 运算时,自动将s1提升到32位,然后与i相加,得到的结果是32位的,而此时
s1=s1+i; 必然报错,执行强转:
s1=(short)(s1+i); 就没问题了.
s1+=i;能编译通过并得到正确结果,而 s1=s1+i; 却报错,是因为它们在类型不同时要区别对待,s1+=i的方式java会对i进行窄化转换,由编译程序自动执行.
java规范中说:
E1 op=E2 实际上等价于 : E1=(T)( (E1)op(E2) )
其中T是E1的数据类型.这种类型转换或者是一个恒等转换,或者是一个窄化转换.
这个说明java是一种强类型的语言,对数据类型的要求是非常严格的,否则会引起混乱.
下面解释一下三种类型转换:恒等转换(相同容量的两个数据类型之间的赋值);拓宽转换(小容量类型赋值给大容量类型);窄化转换(大容量赋值给小容量类型). 实际上,前两种转换都是编译程序自动执行的,而窄化转换则要求必须显式的执行.
总结:根据以上解释就可以做出判断了:该题目是大容量赋值给小容量数据类型,即窄化转换,就要进行强制转换,应该这样:short s1 = 1; s1=(short)(s1+i); 所以第一问是错的。java会对s1+=i的方式自动进行窄化转换,不需要强制进行,所以是可以正常编译的。
二、按+=的运算功能来解释
第一种方式:
short s1 = 1; s1 = s1 + 1;需强行转化
因为short s1=1在栈中开辟了一个short类型的空间;
而s1=s1+1;中s1是short类型,在栈中开辟了一个short类型的空间,而1是int类型,
int类型比short类型大,所以相加后的结果应为比较大的类型,把s1+1的结果赋予short类型的变量s1,固然需要强行转化;
第二种方式:
short s1 = 1; s1 += 1;(可以正确编译)
由于+=运算符有自加功能,定义short s1 = 1;时,开辟了一个空间,当通过+=运算符运算时,只是在原来的栈中进行运算,不需强行转化;
附:java运算符的“提升”现象(运算规则)
在java的算术运算符中要特别主要“提升”(thinking in java)现象,只要类型比int 小(即char byte short)那么在运算之前会自动转换为int.这样一来,最终生成的结果是int 类型。
eg1: byte b1=10;
byte b2=20;
byte n3=b1+b2;
编译不了,报错:Type mismatch: cannot convert from int to byte
应该是:byte n3=(byte)b1+b2; 同理byte 和short.
因此如果想要把结果赋值给较小的类型,就必须使用类型转换。通常,表达式中出现较大的数据类型决定了表达式最终结果的数据类型。
继续解释:当使用+=、-=、*=、/=、%=、运算符对基本类型进行运算时,遵循如下规则:
• 运算符右边的数值将首先被强制转换成与运算符左边数值相同的类型,然后再执行运算,
且运算结果与运算符左边数值类型相同。
在s1=s1+1;中,s1+1
运算的结果是int型,把它赋值给一个 short型变量s1,所以会报错;而在s1+=1;中,由于
是s1是short类型的,所以1首先被强制转换为short型,然后再参与运算,并且结果也是
short类型的,因此不会报错。那么,s1=1+1;为什么不报错呢?这是因为1+1是个编译时可
以确定的常量,“+”运算在编译时就被执行了,而不是在程序执行的时候,这个语句的效果
等同于s1=2,所以不会报错。前面讲过了,对基本类型执行强制类型转换可能得出错误的
结果,因此在使用+=、 -=、*=、/=、%=等运算符时,要多加注意。
修改方法1:s1 = (short)(s1 + 1)
方法2:s1 = (short)(s1 + (short)1)
|