问题
在使用short和byte时,11可能会涉及到短整型和字节型运算,例如下面这段代码片段,两个部分都会编译器都会给出类型不兼容的提示。byte型和short型(包括Byte和Short类型对象)解决方法均为将返回类型强转回byte或short,或者干脆使用int接受计算结果。
问题可以总结为为什么byte和short型运算结果都是int类型。
byte b1 = 1;
byte b2 = 2;
byte b3 = b1 + b2; //编译器爆红
short s = 1;
s = s + 1;//编译器爆红
但byte和short运算时还有一种特殊情况,即使用自增等自运算时却不会爆红,程序可以通过编译。
short s = 1;
s++;//不会爆红
接下来通过查看Java字节码文件的方式分析问题。
原因
byte、short自运算为什么能通过编译
首先使用javap -c命令对下列代码进行反编译,首先分析为什么自运算能够通过编译
byte b = 1;
b++;
反编译结果如下(只摘取main方法部分):
public static void main(java.lang.String[]);
Code:
0: iconst_1
1: istore_1
2: iload_1
3: iconst_1
4: iadd
5: i2b
6: istore_1
7: return
}
在字节码的第4、5、6行可以明显看到,在变量b做完自增后使用了i2b将int型结果自动转回了byte型,随后才存储到局部变量表中。
也就是说,byte和short类型在自增运算时,JVM自动帮我们完成了类型强制转换的工作,所以可以正常通过编译。
为什么byte、short的运算结果会被转换为int型
字节码角度
仍然可以拿上文中的反编译结果做解释。
首先说明一下,在JVM指令集中,部分指令可以分为两个部分来开,即:类型|操作,例如反编译结果中第四行的iadd,见文知意即int add整型自增,相对应的还有其他数据类型的自增版本,比如ladd、fadd、dadd三种。
那么可以看见在反编译结果中,所有的指令都是以i做开头,也就是说从头至尾都byte类型的数据是在JVM中都是以int的形式做读取、保存、运算等操作,进而可以理解为什么使用byte和short类型运算时都需要强转。
指令集角度
了解了上述的内容后,不难产生一个疑问,即为什么不单独为byte和short类型单独做出一系列例如badd、sadd的操作呢?
这是因为Java虚拟机在设计时限制了操作码长度为一个字节,即只有0~255共256条操作码可供设计,由于指令集空间有限,byte和short这两种相对不常用的数据类型的部分运算存取操作都没有被设计,没有被设计的这部分操作实际运行时均将类型转换为int型后使用int操作代为执行(因为小范围转换为大范围,向上转型操作是安全的)。