首先请题主明确java是啥。
好的下面我们说正事,另外我也是借此机会顺便复习一下JVM,这个答案也当我的一个笔记吧,毕竟学艺不精,如果有错误敬请指正,共勉。
------------------------------------------------------
首先,我们有:
下面我们编译它,然后用java bytecode editor打开。
下面查看test method的bytecode:
然后我简单地解释下。
areturn就是callstack返回指令之一,更加明确的说,是引用返回指令,代表返回栈顶的objectref。其它的返回指令还有ireturn(int)、lreturn(long)、dreturn(double)、freturn(float)和return(void),这些指令向调用者返回的值都是栈顶的内容。这里我们的返回值是String,是个reference,所以就用了areturn。
同时我们再次观察,这个method的bytecode中包含两个areturn指令,分别在相对地址9和相对地址25,但是其实,我们可以看到,这个method其实必然从相对地址9的areturn处返回,因为这个method中完全没有areturn之前的跳转指令!唯一的跳转是相对地址14的无条件跳转到相对地址23,而这个跟我们没关系了。
顺便一提,bytecode指令集中的条件跳转指令以if开头,分别是if_acmp、if_icmp、if、ifnonnull和ifnull,看名字应该就能看出来,然后里面你会传入两个operand,分别是true和false时跳转的位置。
扯远了。
我们接着分析返回值。
首先我们看到在相对地址9之前,我们能够见到一下几种指令:ldc - constant pool加载指令(加载到栈顶,如果不明说的话,jvm bytecode指令的默认操作目标就是栈顶)
astore_ - 将栈顶的objectref存入lvs,也就是local variable slot n
aload_ - 从lvs读取一个objectref,存入栈顶。
这里估计你也猜出来了,还有一些类似istore_、iload_的指令。另外,store和load系列的指令还有另一种形式:astore和aload的形式。这两个指令对应的code是不同的,astore_形式的指令,n取值只有0到3,分别对应code 0x4b、0x4c、0x4d和0x4e,而超过了3的,就需要使用astore指令,code是0x3a,后接一个operand。
哦还有一件事,注意看Standard的:
Operand Stack中,..., objectref →
这个表示我们将会弹出栈顶端的objectref,然后我们并不关心剩余的栈中是啥。而如果栈顶不是objectref呢?这个留给你来做实验吧。
(没忍住,帮你做了……
我这里将相对地址2的astore_0改成了istore_0,根据standard,
使用istore_的时候站定必须是个value,而显然我们此时的栈顶是个objectref,于是:
好了又扯远了。
那么我们分析一下:ldc #2 将一个指向cp_info #2的objectref压入栈顶
astore_0 将处于栈顶的指向cp_info #2的objectref放入lvs 0,然后弹出它
aload_0 将lvs 0中的objectref推进栈顶
astore_1 将栈顶的objectref弹出并放入lvs 1
ldc #3 将一个指向cp_info #3的objectref压入栈顶
astore_0 弹出,存lvs 0
aload_1 加载lvs 1,压入(参见4,这里栈顶的objectref指向cp_info #2)
areturn 将栈顶(cp_info #2)的objectref作为返回值返回,执行终止
那么我们分析下返回值:cp_info #2即一开始给result的值,也就是:博格人入侵了! --Dr.Bright (大误……
很好,我们往回看一下第5-6条指令,注意这里我们已经执行了finally block中的内容,即
result = "We secure. We contain. We protect.";
而且事实上,我们的确给result赋值了,lvs 0即result,不过再其之前,javac主动在lsv 1中备份了我们这个method的返回值,最后在7中恢复了它,并最终通过8返回。
至此,相信你已经可以总结出关于finally和return的(至少一部分的)语义了(其实这个玩意应该在Java Lang Specs中就有,不过既然我已经查了一大堆写了一大堆,就不再多说了……)。