趣事:为啥java中一般用int当做循环的控制变量
引言
相信小伙伴在平时写循环啥的,用Eclipse或者IDEA都能很快速的贴出一段循环体来,而且这些循环的控制条件(以标准for循环为例)都是一个int值,哪怕有的时候我们仅仅循环个几十次,但是我们还是使用了int,而不是一个byte或者short,这是为啥呢。今天就来摸一摸这个底
JVM中的循环
想必大家都知道,咱们的java代码最后都是编译成.class文件加载到jvm后,由jvm再转成各自平台cpu能识别的指令才能执行的,其实今天的这个问题,归根结底就跟jvm的指令集有关。jvm的指令集其实只有一个字节长(1<<8)-1就是最多255个指令,所以在jvm里很多类型的操作指令并没有得到全部的支持,比如缺乏byte,char,short类型的直接操作指令,他们都是共用int类型的操作指令的。
说道这里大家可能想到了,我们在学java的时候就听说在java里整形数据默认为int实现,原来是这么个道理。
说到这可能还有小伙伴不太理解,那么就用一个栗子来说明,
//这个栗子取自java 虚拟机规范 SE8 版
//考虑以下循环
void spin(){
int i;
for(i = 0; i < 100; i++){
; //Loop body is empty
}
}
这是一个空循环,我们看看编译器会把它变成什么样:
0 iconst_0 //把int类型的0压入操作数栈
1 istore_1 //从操作数栈弹出栈顶元素,并存入临时变量表中下标为1的位置(就是刚那个0)
2 goto 8 //跳转到指令偏移量为8的指令行
5 iinc 1 1 //临时变量表中下标为1的值自增,增量为1
8 iload_1 //把临时变量表下标为1的值压入操作数栈
9 bipush 100 //把int类型的100压入操作数栈
11 if_icmplt 5 //弹出操作数栈顶的2个值,如果第二个值小于第一个就跳转到指令偏移量为5的行(i<100?->5:)
14 return
详细看注释,解释的应该很清楚了
然后咱们来看看用short值当控制变量会怎么样:
void(){
short i;
for(i=0; i < 100; i++){
; //Loop body is empty
}
}
同样的,我们看看编译之后:
0 iconst_0 //把int类型的0压入操作数栈
1 istore_1 //从操作数栈弹出栈顶元素,并存入临时变量表中下标为1的位置(就是刚那个0)
2 goto 10 //跳转到指令偏移量为10的指令行
5 iload_1 //将临时变量表下标为1的值压入操作数栈
6 iconst_1 //将int类型的1压入操作数栈
7 iadd //弹出操作数栈顶的两个数,相加,然后将结果压入栈
8 i2s //弹出栈中第一个元素,将int类型的值转成short类型的,压回去
9 istore_1 //弹出栈中第一个元素,保存到临时变量表的下标1中
10 iload_1 //将临时变量表下标为1的值压入栈
11 bipush 100 //把int类型的100压入操作数栈
13 if_icmplt 5 //弹出操作数栈顶的2个值,如果第二个值小于第一个就跳转到指令偏移量为5的行(i<100?->5:)
16 return
可以清楚的看到,换成short当控制变量后,多了几个指令,这几个指令的作用就是转型,因为最后要返回的i是个short类型的值,而操作的时候没有直接操作short类型的指令,所以这里才这么麻烦要转来转去。所以如果不是为了那点内存空间,大家还是用int吧