牛客网上一道关于子类父类方法调用的题目
首先上代码,题目是要求写输出。
1 public class Test2 { 2 public static void main(String [] args){ 3 System.out.println(new B().getValue()); 4 } 5 static class A{ 6 protected int value; 7 public A(int v) { 8 setValue(v); 9 } 10 public void setValue(int value){ 11 this.value = value; 12 } 13 public int getValue(){ 14 try{ 15 value++; 16 return value; 17 } catch(Exception e){ 18 System.out.println(e.toString()); 19 } finally { 20 this.setValue(value); 21 System.out.println(value); 22 } 23 return value; 24 } 25 } 26 static class B extends A{ 27 public B() { 28 super(5); 29 setValue(getValue() - 3); 30 } 31 public void setValue(int value){ 32 super.setValue(2 * value); 33 } 34 } 35 }
运行的结果是:22 17 34。与我想的差距很大,下面来单步调试解析一下。
首先new B(),调用B的构造方法。B的构造方法有两行。
构造方法第一行super(5),调用父类A的构造方法,父类构造方法中只有一句setValue(v),这里要非常注意,这里调用的setValue不是A中的而是B中的setValue,可以这么理解:A构造方法中setValue省略了this,而在执行B构造方法时this指的是B,即使调用了父类A的构造方法,this指的也是B,所以这里的setValue调用的是B的setValue。调用B的setValue,跳到31行,32行又调用了父类的setValue(2*5),跳到10行。同理,这里的this指的是B,所以B的成员变量value变为2*5=10。B构造方法第一行结束,此时B的value为10。
构造方法第二行,setValue(getValue()-3),要先计算getValue(),而this中也就是B中没有getValue,这时候往上找(父类找,父类没有再往上找),A中有getValue(),则调用,跳到13行。同理,this指B,所以10+1=11,执行完finally再执行return,所以到finally中时value为11,finally第一行,同理,this指B,所以this.setValue调用的是B中的方法,B中setValue调用父类setValue(2*11),finally打印出的值即为22,,但是这里有个非常要注意的地方,那就是try中return和finally关系。我们知道finally是无论如何都会执行的,即使try中有return,但是在编译器运行到try中return时,return值已经确定,这时在finally中再改变value的值,return的值不会改变,想改变return的值,需要在finally中重新return,这样才会改变,所以打印完22后,try中return的值仍然为11。继续执行外层,setValue(11-3=8),调用B中setValue(8),B中setValue调用父类setValue(2*8=16)。B构造方法第二行结束,此时B的value为16。
接着是,B对象的getValue()语句。B中没有getValue(),调用父类A的getValue(),value++,16+1=17,return17,但是要在finally执行之后。进入finally块之后,调用this.setValue(17),B中setValue(17)调用父类setValue(17*2=34),然后打印34。返回17,main函数中再打印17。
这个题目虽然不难,但是很考验基础,父类与子类方法的关系,try-catch块finally块执行顺序以及编译的结果。

浙公网安备 33010602011771号