题目:
牛客链接: https://www.nowcoder.com/questionTerminal/af8cf04602e045958d13d16d20a1bf02
Test.main() 函数执行后的输出是():
public 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;
} catch(Exception e){
System.out.println(e.toString());
} finally {
this.setValue(value);
System.out.println(value);
}
return value;
}
}
static class B extends A{
public B() {
super(5);
setValue(getValue() - 3);
}
public void setValue(int value){
super.setValue(2 * value);
}
}
}
选项:
A : 11 17 34
B : 22 74 74
C : 6 7 7
D : 22 34 17
由于这道题涉及到执行顺序比较多,所以我觉得个人需要记录一下帮助记忆.
在解题之前可以先看看简单的类的执行顺序https://blog.youkuaiyun.com/u012403290/article/details/68954928
本文解答过程参考:https://blog.youkuaiyun.com/zhumintao/article/details/53818972
代码运行过程:
运行代码,对于一个普通类来说会先执行他的静态代码块,然后是main()方法,然后是非静态代码块,然后是构造方法.
对于当前这个类(class Test),会先执行main方法
于是来到这一行:
在这一行中,会new一个B的对象,并且调用B的getValue方法,那么此时开始构造B的实例,进入B的构造方法
由于B继承自A,并且A没有无参构造,所以B必须显示调用A的构造方法,并且传入参数.下面就会进入到A的构造方法
可以看到,此时A的构造方法又会调用setValue方法,那么这里需要注意的是:
A类和B类都有一个setValue方法,但是此时我们是为了创建B的实例,所以这里仍然处于B的构造方法执行过程,所以会默认调用B的setValue方法,如果B中没有这个方法,那么就会调用A中的这个方法.
那么此时就会进入B的setValue方法
此时可以看到B又调用了父类的setValue方法,并且传入的参数是 2 * 5,下来进入父类的此方法
此时A中成员属性value就被值为2 *5 即 10,此时B的构造方法中,调用A的构造方法过程已经结束了,下面执行B构造方法中的setValue方法.
注意到B中的setValue方法又会调用getValue方法,但是B中没有这个方法,所有会调用父类A的getValue方法,下面就来到A的getValue方法.
那么此时A的getValue方法会给A的成员变量value自增,并且返回value,没有触发异常,然后会执行finally中的代码
运行到这里可以看到A中的value已经自增成了11,此时finally又会调用setValue方法,这里需要注意的是,this.setValue(value)中的this指的是B的实例的引用,因为现在还处于B的构造方法过程,所以会调用B的setValue方法.
此时B中的setValue方法会嗲用父类的setValue方法,并传入2 * 11
此时value就变成了22,此时this.setValue(value)就执行完了,最后输出value,22
到这儿getValue()方法就执行完了,但是需要注意的是,虽然此时value是22,但是在A的getValue方法的 try的代码块中,已经返回了value,并且返回时value的值为11,所以这个方法的返回值级已经保存下来了,是11,而就算finally中再次对value进行了改变,返回的值也不会被改变.
此时继续执行B类构造方法中的setValue(getValue() - 3)
执行时得到setValue(11 - 3)
即setValue(8)
接下来执行B的setValue方法.
B又调用A的setValue方法,并传入参数2 * 11
则进入A的setValue方法
此时value变为16
到这儿B类的构造方法就全部执行完了,也就是new B()
然后又调用了该对象 的getValue()方法,B类没有,但是父类A有,所以
继续try{ }、catch{ }、finally{ },成员变量value为16
然后value++,再返回
这时getValue()的返回值已经确定了,就是17
然后到finally{ },又是this.setValue(value)
这个this指的是B类的this,所以调用B类的setValue(int value).
又是super.setValue(2 * value),调用A类的setValue(),并把2 * 17作为参数传递过去
把参数赋给成员变量value,这时this.setValue(value)就执行完了,此时的value为34。最后输出value。
此时的getValue()方法的返回值是17,前面已经提到了
整个new B().getValue()已经结束了
最后又输出了getValue的返回值,也就是17
最后的输出结果是:
也就是先前的选项D