finally结构的注意点(二)

我在上一篇中总结了java中finally结构的3个典型问题,以及展示了finally结构可能产生的副作用。在这一篇中,我将继续展示finally的一些特点。
如果try块中有导致try块提前退出的语句(如return语句和throw语句,我们以return语句为例),那么finally会在return语句之前先执行。
比如有如下函数:
	public static int testVariableChangeInFinally()
	{
		int i=0;
		try{
			i=1;//步骤1
			return i;//步骤2
		}finally{
			i=2;//步骤3
		}
	}

那么,函数真正的执行顺序应该是 步骤1->步骤3->步骤2。然而执行该函数时,函数的返回值却是1。why?这导致我们有2个新的假设:

1,执行顺序不是我们想的那样;
2,步骤3根本就没执行;

第2个假设是很好排除的,我们在步骤3下面再加入一条输出语句,形成代码如下
	/**
	 * 
	 * @return
	 */
	public static int testVariableChangeInFinally()
	{
		int i=0;
		try{
			i=1;
			return i;
		}finally{
			i=2;
			System.out.println("finally");
		}
	}

运行函数,发现控制台确实打印出了finally字符串,说明步骤3确实是被执行过了。说明假设2不成立。(如果是怀疑是乱排序了,那么可以用eclipse一步一步调试)

难道执行顺序不是步骤1->步骤3->步骤2吗?答案是只对了1半。
实际上,在虚拟机内部,return语句是分为2步的,第一步是把返回值压入到调用者的栈中,第二步是返回到调用者的栈。因此,我们可以把我们的代码想象成如下形式:
	/**
	 * 
	 * @return
	 */
	public static int testVariableChangeInFinally() {
		int i = 0;
		try {
			i = 1;//步骤1
			int temp = i;//步骤2
			return temp;//步骤3
		} finally {
			i = 2;//步骤4
		}
	}

因此,执行顺序应该是 步骤1->步骤2->步骤4->步骤3
所以,函数也就返回了1,而不是2。我们也可以通过eclipse的单步调试观察i值的变化,发现i也确实变成了2。

你可能感兴趣的:(eclipse,虚拟机)