Java中子类和父类相关方法的执行顺序

无心中看到下面一个题目,你们一块儿来看看最后的输出结果是什么。反正我看完以后,用IDE测试后感受知识点获得巩固了。ide

 1 /**
 2  * 函数执行顺序测试
 3  * Created by 萌小Q on 2017/5/17 0017.
 4  */
 5 public class ExeSeqTest {
 6 
 7     public static void main(String [] args){
 8         System.out.println(new B().getValue());
 9     }
10     static class A{
11         protected int value;
12         public A(int v) {
13             setValue(v);
14         }
15         public void setValue(int value){
16             this.value = value;
17         }
18         public int getValue(){
19             try{
20                 value++;
21                 return value;
22             } catch(Exception e){
23                 System.out.println(e.toString());
24             } finally {
25                 this.setValue(value);
26                 System.out.println(value);
27             }
28             return value;
29         }
30     }
31     static class B extends A{
32         public B() {
33             super(5);
34             setValue(getValue() - 3);
35         }
36         public void setValue(int value){
37             super.setValue(2 * value);
38         }
39     }
40 }

执行结果:函数

22
34
17
View Code

大家答对了么?哈哈,如今来看一下代码具体执行状况:测试

一、首先是main方法,new了一个B对象,而后就是调用该对象的getValue()方法this

二、执行B类的构造方法spa

三、执行B类构造方法里面的super方法,即执行B的父类A的构造方法。3d

四、接下来就是执行setValue()方法了,可是此时A类和B类都有一个setValue()方法,到底执行哪个呢,我一开始认为是A类的setValue()方法。code

但在A类的构造方法中执行setValue()方法时,你是否是看到了,它执行的是子类B的setValue()方法。对象

显然这须要巩固一个知识点:当子类重写了父类的函数,那么子类的对象若是调用该函数,必定调用的是重写事后的函数。能够经过super关键字进行父类的重写函数的调用。blog

由于如今正在执行的是B类的构造方法,因此默认先会调用B类中的方法,若是B类中没有,才会调用其父类A中的方法继承

五、接下来到super.setValue(2 * value),即执行A类的setValue()方法,这时,A类的成员变量value应该就变成了10

 六、这时B类的构造方法中的super(5)就执行完了,而后就到了setValue(getValue() - 3)方法

七、接着执行getValue()方法,首先在B类中找,但B类没有getValue()方法,因此就执行A类中的getValue()方法,A类中确定是有的,要否则编译就不会经过

八、而后就开始执行try、catch、finally这一块,给A的成员变量value自增,从以前的10变为11,而后直接返回value,没有捕获异常,继续到finally里面的this.setValue(value)

 

九、而后这个this指的究竟是A类仍是B类呢,答案是B类,由于如今是在执行B的构造方法,因此this指的应该是B类,即调用B类的setValue(int value)方法。

十、而后又super.setValue(2 * value);执行父类A的setValue(int value),把2 * 11做为参数传递,A类的setValue(int value)把传进来的value值赋给了A的成员变量value,变成了22。

十一、而后this.setValue(value)就执行完了,最后输出value,22

十二、到这儿getValue()方法就执行完了,可是有一点须要注意,此时的value为22,可是getValue()的返回值确是11,由于在try{ }中已经return了,因此这个方法的返回值已经保存下来了,是11,即便finally{ }里面又对value的值作出了改变,可是getValue()的返回值是不会变的(除了finally里面也有return返回值,它会覆盖前面try的返回值)。接着继续执行B类构造方法中的setValue(getValue() - 3);getValue()是11,因此B的setValue(int value)方法的参数就为8,接着又到了super.setValue(2 * value)

1三、调用A类的setValue(int value)方法,同时将参数赋值给A类的成员变量value,此时value变为16

1四、到这儿B类的构造方法就所有执行完了,也就是new B(),而后又调用了该对象 的getValue()方法,B类没有,可是父类A有,

 

继续try{ }、catch{ }、finally{ },A类的成员变量value为16,而后value++,再返回,这时getValue()的返回值已经肯定了,就是17,即便在finally中对value作出改变,其返回值不会变。而后到finally{ },又是this.setValue(value),前面已经说过了,这个this指的是B类的this,因此调用B类的setValue(int value)

接着又是super.setValue(2 * value),调用A类的setValue(),并把2 * 17做为参数传递过去

把参数赋给A的成员变量value,这时this.setValue(value)就执行完了,此时的value为34。最后输出value。

须要注意的是,此时的getValue()方法的返回值是17,这个前面已经提到了,到这儿,整个new B().getValue()就执行完了,最后又输出了getValue的返回值,也就是17。因此整个过程执行完后的输出结果是2二、3四、17。。。。。。

这道题虽然饶了不少弯,可是咱们作完后发现总体过程其实并非很复杂,就是子类继承父类,调用方法时先是调用子类中的方法,若是没有就调用父类中的方法,还有一点就是try{ }、catch{ }、finally{ }返回值的问题,一旦try{ }中返回了某一个值,若是finally有返回值,finally中的返回值会覆盖try的返回值,若是finally没有返回值,就是try中的返回值。掌握了这些,这道题就显得很简单了。

 

Java初始化顺序如图:

相关文章
相关标签/搜索