昨天在通过jvm规范搞懂了java中类循环依赖的编译问题,讨论见
http://topic.youkuaiyun.com/u/20111008/11/aede24de-a712-470c-9315-8796301c548f.html
然后突发奇想想了解下java的异常处理原理,只是略微看懂了finally,下面是个人关于一个网上小问题的见解,欢迎各位指正
public class Exception2 {
int x = 1;
public static void main(String args[]){
Exception2 e = new Exception2();
System.out.println(e.getValue());
System.out.println(e.x);
System.out.println(e.xx());
}
int getValue(){
try{
return x;
}finally{
x = 2;
}
}
int xs(){
return x;
}
int xx(){
x = 2;
return x;
}
}
打印出的值分别为 1,2,2
第一个值之所以为1,见下面字节码
int getValue();
Code:
0: aload_0
1: getfield #2; //Field x:I
4: istore_1 //本来是要直接return的,但是因为finally的存在,保存当前状态,并之后执行finally块中的代码
<<<5: aload_0
6: iconst_2
>>>7: putfield #2; //Field x:I
10: iload_1 //iload_1 对应istore_1时保存进去的值,即在第一行中调用getfield得到的1
11: ireturn
12: astore_2 //保存现场, 即执行到什么地方
13: aload_0
14: iconst_2
15: putfield #2; //Field x:I 18: aload_2 //恢复现场
19: athrow
Exception table:
from to target type
0 5 12 any
12 13 12 any
int xs();
Code:
0: aload_0
1: getfield #
2; //Field x:I
4: ireturn
int xx();
Code:
0: aload_0
1: iconst_2
2: putfield #2; //Field x:I
5: aload_0
6: getfield #2; //Field x:I
9: ireturn}
<<<Code....>>>中的代码时x=2对应的字节码.可以发现xx方法在ireturn之前执行了getfield方法,所以返回的是更改后的值而getValue方法中没有在return前重新getfield,故为1猜测,之所以能保证finally一定会被执行到,是因为当java在检测try中的return后,就将finally中的代码插入了return之前,之前是loadx->return,插入之后变为loadx->finally block->return。java并没有做额外的工作去重新load x的值,即便
x在finally block中被改变了
下面是引用到的一点jvm指令的知识
aload_0:aload_0 is supposed to push 'this' on to the stack.Not quite … aload_0 reads the first argument of the method. In member functions, this happens to be the this reference. But main is not a member function, it’s astatic function so there is no this argument, and the true first argument of themethod is args.ireturn:Pops an int from the top of the stack and pushes it onto the operand stack of the invokerathrow:https://www.vmth.ucdavis.edu/incoming/Jasmin/ref-athrow.htmlputfield:putfield sets the value of the field identified by <field-spec> in objectref(a reference to an object) to the single or double word value on the operand stack
顺便附上一些指令的含义:(聪明的读者一定能推断出i代表int,f代表fload,d代表double,a代表引用类型)
istore x: 将int型变量存到本地变量. x代表一个本地变量地址号. 如istore 即将int型变量存到本地变量4去。
iload x: 将制定的int型变量x推送至栈顶。aload_0是指拿到this。
iconst x: 将int型常量推送至栈顶。
ireturn: 故名思议,从方法返回int,一般在返回之前都会iload一下,然后再从栈顶中取值返回。