相信大家在面试中,或者其他情况下经常会看到这样的一道题,下面inc()方法调用后的返回值是什么,答案大家自己去执行下程序或者问度娘之后应该都知道了,在方法没有异常的时候,返回的是1,出现Exception异常的时候返回的是2,出现Exception以外的异常致使方法非正常退出时,没有返回值。但这样的结果在虚拟机的实现原理是什么呢,我想很多童鞋是不知道的。
public int inc() {
int x;
try{
x = 1;
return x;
} catch(Exception e) {
x = 2;
return x;
}finally {
x = 3;
}
}
图1-1
如图1-1,是我用javap -verbose执行该方法后得到的该方法对应的Class文件的字节码
从Exception table可以看到在正常执行时,是从第1步开始到第7步返回,首先将1赋值第二个本地变量(第1步-第2步),这里的第二个本地变量就对应着x,再将x复制一份存入第三个本地变量(第3步-第4步)。接着执行finally中的赋值,将3赋值给x存入第二个本地变量,读取第三个本地变量到操作栈顶,即1,并调用ireturn指令以int形式返回(第5步-第7步)。
如果报Exception,第4步执行之后将执行第8步,将2赋值给x存入第二个本地变量,复制2到第四个本地变量,接着执行finally中的赋值,将3赋值给x存入第二个本地变量,读取第四个本地变量到操作栈顶,即2,并调用ireturn指令以int形式返回(第8步-第16步)。
如果出现其他状况,将直接跳转到第17步,将3赋值给x存入第二个本地变量。将异常推送至栈顶并抛出。没有调用ireturn,没有返回值。
因此,才得到上面的结论,现在童鞋们都知道 了吧= =
虚拟机字节码指令说明:
iconst_{i} : 将int型i推送至栈顶
istore_{i} : 将int型值存入第i+1个本地变量
iload_{i} : 将第i+1个int型本地变量推送至栈顶
ireturn : 从当前方法返回int
astore : 将栈顶引用型数值存入指定本地变量
aload : 将指定的引用类型本地变量推送至栈顶
athrow : 将栈顶的异常抛出