11.1转换操作码
Java虚拟机包括许多进行基本类型转换工作的操作码,这些执行转换工作的操作码后面没有 操作数,转换的值从桟顶端获得。Java虚拟机从栈顶端弹出一个值,对它进行转換,然后再把转 换结果压入栈。进行int、long, float和double类型之间转换的操作码如表11-1所示,针对这四种 类型之间的每一种可能的类型转换,都存在相应的操作码。
如表11-2所示的操作码是把int类型转换为比int类型占据更小空间的数据类型。这些操作码 从操作数找中弹出一个int类型值,将它转换为能用byte、short或char类型描述的int类型值,然后 ,把这个转换后的int类型值压人栈。i2b指令将弹出的int类型值截短为byte类型,然后再对其进 行带符号扩展,恢复成int类型。i2s指令将弹出的int类型值截短为short类型,然后再对其进行带 符号扩展,恢复成int类型。i2c指令将弹出的int类型值截短为Char类型,然后再对其进行零扩展 恢复成int类型。
Java虚拟机中没有把long、float, double类型值直接转换为比int类型占据更小空间的数据类 型的操作码。因此,把float类型值转换为byte类型需要两个步骤:首先,float类型值必须通过f2i 指令转换为int类型值,然后,所得的int类型值再通过i2b指令转换成byte类型值。
尽管有操作码可以把int类型值转换为比int类型值占据更小空间的数据类型(byte、short和 char),但并不存在执行相反方向转换操作的操作码。因为任何byte、short和char类型值在压入找的时候,就已经有效地被转换成int类型值了。从数组或者堆中的对象中接受byte、short和char 类型值的指令和把这些值压入找的指令都会把它们转换为int类型值。这些指令将在第15章叙述。
涉及byte、short和char类型的运算操作首先会把这些值转换为int类型,然后对int类型值进行 运算,最后得到int类型的结果。因此,如果把两个byte类型值相加,最后会得到一个int类型的 结果。如果需要得到byte类型结果,必须将这个int类型的结果显式转换为byte类型。例如,下面 的代码会导致编译失败:
// On the CD-ROM in file opcodes/ex1/BadArithmetic.java
class BadArithmetic {
static byte addOneAndOne() {
byte a = 1;
byte b = 1;
byte c = a + b;
return c;
}
}
该操作能够通过javac的编译,并产生GoodArithmetic.class文件。此文件包含了如下的addOneAndOne()方法的字节码序列:
0 iconst_1 //push int constant 1.
1 istore_0 //pop into local variable 0,which is a:
//byte a=1;
2 iconst_1 //push int constant 1 again.
3 istore_1 //pop into local variable 1,which is b:
//byte b=1;
4 iload_0 //push a (a is already stored as an int in
//local
//variable 0).
5 iload_1 //push b (b is already stored as an int in
//local
//variable 1).
6 iadd //Perform addition.Top of stack is
// now (a+b),an int.
7 i2b //Convert int result to byte (result still
//occupies 32 bits).
8 istore_2 // Pop into local variable 3,which is
// byte c:byte c=(byte)(a+b);
9 iload_2 // Push the value of c so it can be
// returned.
10 ireturn // addition: return c;
该Convert ()方法演示了Java虚拟机中将int类型值转换为byte类型值的方式。imInt变量开 始的值为125,每经过一次循环,它都会自增1,并转换为byte类型。然后,它的值变为原值与 -1的乘积,最后再次转换为byte类型。这个模拟过程可以快速地显示出在byte类型有效范围的边 界上发生的事情。
byte类型的最大值为127,最小值为-128.在这个范围内的int类型值被直接转换为byte类型值,而当int类型值超出这个有效范围时,事情就变得有趣起来。
Java虚拟机通过截短和带符号扩展的方式将int类型值转换成为byte类型值。long、int、 short 和byte类型的最高位(“符号位”)指出此int类型值是正还是为负。如果符号位为0,值为正;如果符号位为1,值为负。byte类型的第7位为符号位。从int类型值转换到byte类型值的时候,第7位的值将会被拷贝到第8位到第31位。这样就产生了一个int类型值,这个值与原来int类型值被转换为byte类型值后所获得的结果具有相同的数值。在执行完截短和带符号扩展操作后,这个int类型变量中将容纳一个有效的byte类型的值。
applet模拟列出了一个超出byte类型有效范围的int类型值转换为byte类型时所发生的事情。 例如,imlnt变量的值为128 (0x00000080),它被转换为byte类型后,所得到的byte类型值为-128 (Oxffffff8O)。然后,当imlnt变量的值为-129 (Oxffffff7f)时.它被转换为byte类型后所得到的值为127 ( 0x0000007f )。