java return与finally执行顺序测试

       今天面试一家公司,笔试题目有一道是考察finally块与return的执行顺序,由于以前没去关注,这次又正好遇见,所以做一次记录。

先看代码:

public class Test2 {
	private static int i = 0;
	public static int finallyTest(){
		try{
			System.out.println("enter try block");
			i += 1;
			return i;
		}finally{
			System.out.println("enter finally block");
			i += 1;
			//return i;
		}
	}
	
	public static void main(String[] args) {
		System.out.println(finallyTest());
		System.out.println(i);
	}
}

输出结果为:

enter try block
enter finally block
1
2

可能有部分同学可能认为会返回2,2,可以理解,但是如果你看到这个结果就产生了finally块的代码无法影响try块的返回值的想法,那就又错了(比较简单的情况,在finally里加上return语句,就会覆盖try里的return,但是不推荐这么做,因为这与finally的设计初衷背道而驰),我们再看下面代码:

public class Test2 {
	private static Integer i = new Integer(0);
	public static Integer finallyTest() throws IllegalArgumentException, IllegalAccessException{
		try{
			System.out.println("enter try block");
			i += 1;
			return i;
		}finally{
			System.out.println("enter finally block");
			Class<Integer> clazz = (Class<Integer>) i.getClass();
			Field[] fields = clazz.getDeclaredFields();
			Field f = null;
			for(int i = 0;i < fields.length;i++){
				if("value".equals(fields[i].getName()))
					f = fields[i];
			}
			f.setAccessible(true);
			f.setInt(i, 2);
		}
	}
	
	public static void main(String[] args) throws IllegalArgumentException, IllegalAccessException {
		System.out.println(finallyTest());
		System.out.println(i);
	}
}

返回结果为:

enter try block
enter finally block
2
2

只是把案例1的int类型改为了Integer类型,就产生了完全不同的结果

下面对着两种结果做解释:

1、如果try块里执行到return语句,首先会把return后面的语句执行,并把结果(实则是一个指针)缓存,但是不会立即返回,会先去检测有没有finally块,如果有,则执行finally块,然后再把缓存的指针的返回

2、严格意义上,finally块的确没法影响try块里的返回值(这里的返回值指的是指针),但是可以改变指针指向的对象

3、有了上面的理解,我们再回头看上面两个案例,对于1,当i设为int类型时,try遇到return语句,此时i的值为1,以下为个人理解:此时会把i的值的内存地址缓存起来,由于i的类型为基本类型,所以会在常量池中分配空间,也就是说此时缓存的结果为一个指向常量池中保存1的内存空间的地址,假设为0x01;接着执行finally块,finally块对i执行了++操作,此时会直接操作0x01所指向的内存里的值吗?当然不会,常量池的值都是不会变的(因为常量池的设计就是为了提高内存利用率),此时只会再在常量池开辟一片空间,用来存储i+=1后的值,也就是2,然后把2的内存地址返回给i,假设为0x02。最后返回缓存的0x01,此时0x01仍指向常量池中的“1”,而不是“2”;如果理解了案例1,再来看2就容易多了,首先,案例2中i的类型是Integer类型,也就是说i是指向一个堆里对象的地址,当执行到try块里的return语句时,i指向堆里对象的值为1,假设地址为0x01,也就是把0x01缓存起来(如果finally里没有return语句,那么这个地址就是返回值),然后执行finally块的代码,finally块操作的i仍指向堆里的同一对象,此时对i进行++操作,不会另外开辟空间,直接对堆里面的Integer对象的value域进行+1操作,所以改变的就是0x01所指向的对象,然后返回缓存的0x01,此时自然变为了2

 

总结:

java语言摒弃了C语言以及C++中指针的概念,无疑简化了我们的开发,但是同时也大大提高我们理解内存存储的难度,总之有利有弊吧。对于本期讨论的主题,总结如下:如果try块里返回值为基本类型(包括String),则finally里影响不到try块里的返回值,但是如果try块里返回的是引用类型,那么finally块是完全有可能影响返回结果的

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值