大家先看一下下面的代码
public class Main {
public static void main(String[] args) {
byte a = 1;
byte c = 2;
byte b = a + c;//编译报错
}
}
其中byte b = a + c;
这句代码会报一个类型不匹配的错误,说不能将int
类型转换成byte
类型。WTF?!,两个byte类型的变量相加再赋值给一个byte类型变量,这是哪门子的类型不匹配呀,那个int
又是哪来的!然后改成byte b = (byte) (a + c);
又能行了。这几句代码,其实包含了很多的Java的秘密,容我慢慢说来。
首先你应该知道的是,byte a = 1;
和byte c = 2;
这两句右边的数值1和2是一种叫字面值常量的东西,像"abc"
是字符串类型的字面值常量,Java编译器会把数值的字面值常量默认为int类型的。
大家应该都清楚,将一个int型变量赋值给一个byte型变量就会产生我一开始说的类型不匹配错误,如下面的代码
int a = 1;
byte b = a;
像1和2虽然是int型数据,但是它们并不是一个int型变量记录的值,它们在编译的时候就是已知的了,所以只要不超出byte范围直接赋值给byte变量还是能行的,要是超出了byte范围如128那就会报一个类型不匹配错误。
那么回到问题所在,为什么两个byte类型变量相加再赋值给byte类型变量会报错呢?根据错误信息可以得知a + b
后所得到的结果应该是一个int类型数据。所以我们真正要弄清楚的是为什么两个byte变量相加会得出一个int类型数据。
这个时候就要谈到Java虚拟机搞的一个小动作了。虚拟机遇到涉及byte、short和char类型的运算操作首先会把这些值转换为成int类型,然后对int类型值进行运算,最后得到int类型的结果,就连boolean类型也会变成int类型的0或1。所以这就是为什么两个byte变量相加会得出一个int类型数据,所以short和char也会出现类似的问题。
至于虚拟机为什么要这么做,我在网上找到了一个感觉比较靠谱的答案
因为32位的系统(x86系列的寄存器啥的)一次能够处理4个字节,也就是32位,所以直接搞32位的数据就不必进行什么数据的对齐 啊补全啊什么的。。换句话,为了速度喽。
另外对于64位CPU和64位开发运行环境,使用long更好,因为long才是64位的。