一道关于try catch finally return的Java笔试题的总结

题目概述

这是一道Java的笔试题,所考察的知识点有类的继承和try、finally、return的执行顺序。

题目源代码

package test;

class Test {
    public static void main(String[] args) {
        System.out.println(new B().getValue()); 
    }
    static class A {
        protected int value ;
        public A (int v) {
            setValue(v);
        }
        public void setValue(int value) {
            this.value= value;
        }
        public int getValue() {
            try {
                value ++;
                return value;
            } finally {
                this.setValue(value); 
                System.out.println(value);
            }
        }
    }
    static class B extends A {
        public B () {
            super(5);
            setValue(getValue()- 3);
        }
        public void setValue(int value) {
            super.setValue(2 * value);
        }
        
    }
}

上述的代码结构较为简单,其目的是在主函数中实例化一个B的对象,并调用其的getValue()方法,同时将其返回值打印到console中。

运行结果

22
34
17

分析过程

本程序,主要有两个难点需要理解:第一,super(5)的具体如何执行;第二,在getValue()中的try return finally的执行顺序,由此影响的value值的变化和return的返回值为多少。

super(5)的执行:

显然,在B的构造器中,调用了父类A的构造器,继而调用了setValue()方法。此处的setValue()是省略了this关键字,而this表示的是当前对象,当子类调用父类的构造器,此处的对象为子类的对象,所以this代表的是一个B的对象,从而先在B中查找是否有重载的setValue()方法,若有则执行,无则向上查找。
当执行B的setValue()时,调用了父类的value成员变量,并利用super.setValue()给value进行第一次赋值。

getValue()的执行:

根据继承的方法调用的规则,不难理解getValue()调用了父类的方法,在getValue()中,try代码块执行的语句有value++,return value,finally执行的代码块为this.setValue(value),以及打印value的值。
首先,try执行到return时,会去查找有无finally代码块,若有则先执行finally,没有就继续执行return。当去执行finally的时候,return会把当前value的值暂存起来,等finally代码块的执行完毕,再去返回这个暂存(这是根据打印出的结果进行的一个猜测,在后面有个简单的证明) 的value的值。其等效于以下代码:

public int getValue() {
	try {
		value ++;
//		return value;
		int id1 = value;
        return id1;
        
	} finally {
		this.setValue(value); 
        System.out.println(value);
	}
}

所以,此处的所返回的value值是try代码块执行完毕的值。在finally中,调用this.setValue()方法,this指代当前对象,当前对象为B的一个对象,所以此处的setValue执行的是B中的方法,和A的构造器中的setValue()一样,此处也可以省略this,得到的结果是一样的。

代码中value值的变化过程

由上述的理解,可以得到下述的value值的变化

代码value
super(5)5*2=10
getValue():value++10+1=11(return)
getValue():this.setValue()11*2=22(first print)
getValue()11
setValue(getValue()-3)2*(11-3)=16
new B().getValue():value++16+1=17(return)
new B().getValue():this.setValue()17*2=34(second print)
new B().getValue()17(third print)

try finally return对所操作的值的影响

正如上述所猜想的,return在返回的时候,会声明一个同类型的临时变量去接收return关键字后面表达式的值,并且等finally执行完毕后,再返回临时变量的值。

public int test(){
	int number = 10;
	try{
		return ++number;
	}
	finally{
		number+=2;
		System.out.println("number:"+number);
	}
}

此处console中会打印出13,但是test()的返回值为11。即下述代码等价。

//return ++number ;
int id1 = ++number;
return id1;

若将++number改为number++,即为如下代码:

public int test(){
	int number = 10;
	try{
		return number++;
	}
	finally{
		number+=2;
		System.out.println("number:"+number);
	}
}

此时,return暂存的是number的值,暂存完毕后,number再自增加。等效于下述代码:

//return number++ ;
int id1 = number++;
return id1;

此时,number会先赋值,再自增加。此处console中会打印出13,但是test()的返回值为10。

若return后表达式是Long,String等不可变类型,或者是引用类型,道理都是类似的。只不过,引用类型返回的是一个指针,若在finally中对于该指针指向地址空间的值有所改变,返回的引用所指向的地址中的值也会改变。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值