Java中子类和父类相关方法的执行顺序
2017-08-19 17:48
190 查看
Java中子类和父类相关方法的执行顺序
无意中看到下面一个题目,大家一起来看看最后的输出结果是什么。反正我看完之后,用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 }
执行结果:
![](http://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif)
22 34 17
你们答对了么?哈哈,现在来看一下代码具体执行情况:
1、首先是main方法,new了一个B对象,然后就是调用该对象的getValue()方法
![](http://images2015.cnblogs.com/blog/690102/201705/690102-20170517165041494-837551757.png)
2、执行B类的构造方法
![](http://images2015.cnblogs.com/blog/690102/201705/690102-20170517165112322-491558840.png)
3、执行B类构造方法里面的super方法,即执行B的父类A的构造方法。
![](http://images2015.cnblogs.com/blog/690102/201705/690102-20170517165216432-277315944.png)
4、接下来就是执行setValue()方法了,但是此时A类和B类都有一个setValue()方法,到底执行哪一个呢,我一开始认为是A类的setValue()方法。
但在A类的构造方法中执行setValue()方法时,你是不是看到了,它执行的是子类B的setValue()方法。
显然这需要巩固一个知识点:当子类重写了父类的函数,那么子类的对象如果调用该函数,一定调用的是重写过后的函数。可以通过super关键字进行父类的重写函数的调用。
因为现在正在执行的是B类的构造方法,所以默认先会调用B类中的方法,如果B类中没有,才会调用其父类A中的方法。
![](http://images2015.cnblogs.com/blog/690102/201705/690102-20170517165551838-647245874.png)
5、接下来到super.setValue(2 * value),即执行A类的setValue()方法,这时,A类的成员变量value应该就变成了10
![](http://images2015.cnblogs.com/blog/690102/201705/690102-20170517170101713-950346853.png)
6、这时B类的构造方法中的super(5)就执行完了,然后就到了setValue(getValue() - 3)方法
![](http://images2015.cnblogs.com/blog/690102/201705/690102-20170517170434807-2012580169.png)
7、接着执行getValue()方法,首先在B类中找,但B类没有getValue()方法,所以就执行A类中的getValue()方法,A类中肯定是有的,要不然编译就不会通过
![](http://images2015.cnblogs.com/blog/690102/201705/690102-20170517170534041-598691042.png)
8、然后就开始执行try、catch、finally这一块,给A的成员变量value自增,从之前的10变为11,然后直接返回value,没有捕获异常,继续到finally里面的this.setValue(value)
![](http://images2015.cnblogs.com/blog/690102/201705/690102-20170517170633275-773317473.png)
9、然后这个this指的到底是A类还是B类呢,答案是B类,因为现在是在执行B的构造方法,所以this指的应该是B类,即调用B类的setValue(int value)方法。
![](http://images2015.cnblogs.com/blog/690102/201705/690102-20170517170730697-83158562.png)
10、然后又super.setValue(2 * value);执行父类A的setValue(int value),把2 * 11作为参数传递,A类的setValue(int value)把传进来的value值赋给了A的成员变量value,变成了22。
![](http://images2015.cnblogs.com/blog/690102/201705/690102-20170517170823885-2086341829.png)
11、然后this.setValue(value)就执行完了,最后输出value,22
![](http://images2015.cnblogs.com/blog/690102/201705/690102-20170517170928197-1927458230.png)
12、到这儿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)
![](http://images2015.cnblogs.com/blog/690102/201705/690102-20170517171115228-440197476.png)
13、调用A类的setValue(int value)方法,同时将参数赋值给A类的成员变量value,此时value变为16
![](http://images2015.cnblogs.com/blog/690102/201705/690102-20170517172604416-1669277818.png)
14、到这儿B类的构造方法就全部执行完了,也就是new B(),然后又调用了该对象 的getValue()方法,B类没有,但是父类A有,
![](http://images2015.cnblogs.com/blog/690102/201705/690102-20170517172704775-1399781446.png)
继续try{ }、catch{ }、finally{ },A类的成员变量value为16,然后value++,再返回,这时getValue()的返回值已经确定了,就是17,即使在finally中对value做出改变,其返回值不会变。然后到finally{ },又是this.setValue(value),前面已经说过了,这个this指的是B类的this,所以调用B类的setValue(int
value)
![](http://images2015.cnblogs.com/blog/690102/201705/690102-20170517173025963-1882711430.png)
接着又是super.setValue(2 * value),调用A类的setValue(),并把2 * 17作为参数传递过去
![](http://images2015.cnblogs.com/blog/690102/201705/690102-20170517173201978-550927364.png)
把参数赋给A的成员变量value,这时this.setValue(value)就执行完了,此时的value为34。最后输出value。
![](http://images2015.cnblogs.com/blog/690102/201705/690102-20170517173237447-235037179.png)
需要注意的是,此时的getValue()方法的返回值是17,这个前面已经提到了,到这儿,整个new B().getValue()就执行完了,最后又输出了getValue的返回值,也就是17。所以整个过程执行完后的输出结果是22、34、17。。。。。。
这道题虽然饶了很多弯,但是我们做完后发现整体过程其实并不是很复杂,就是子类继承父类,调用方法时先是调用子类中的方法,如果没有就调用父类中的方法,还有一点就是try{ }、catch{ }、finally{ }返回值的问题,一旦try{ }中返回了某一个值,如果finally有返回值,finally中的返回值会覆盖try的返回值,如果finally没有返回值,就是try中的返回值。掌握了这些,这道题就显得很简单了。
Java初始化顺序如图:
[align=left][/align]
-------------我是低调的分割线--------------------------
如果对你有帮助,可以点击“推荐”哦`(*∩_∩*)′
![](http://files.cnblogs.com/files/Qian123/rabbit.gif)
![](http://files.cnblogs.com/files/Qian123/rabbit.gif)
![](http://files.cnblogs.com/files/Qian123/rabbit.gif)
![](http://files.cnblogs.com/files/Qian123/rabbit.gif)
相关文章推荐
- Java继承中父类子类构造方法、静态代码块、非静态代码块的执行顺序
- java继承中父类和子类静态、非静态代码块,构造函数,静态方法的执行顺序
- Java子类继承父类,构造方法的执行顺序问题
- 【JAVA】探究JAVA父类子类静态代码块、静态变量、构造方法的执行顺序
- JAVA父类子类静态代码块、静态变量、构造方法的执行顺序
- java父类子类中静态块非静态块构造方法的执行顺序和继承
- java父类子类静态块、块、构造方法的执行顺序
- 关于java中子类,父类中,静态代码块: staic{},动态代码块:{},构造方法,类属性,对象属性等执行顺序做个总结:
- java中父类的静态代码块,非静态代码块,构造方法,子类的静态代码块,构造方法等先后执行顺序
- 子类继承父类中的static模块、构造方法执行顺序及java多态性
- JAVA中静态代码块、构造方法、Super()父类与子类之间执行顺序
- java中 静态成员、实例成员、构造方法在子类和父类中的执行顺序
- 子类、父类各种方法的执行顺序
- Java基础-重写-子类重写父类中的方法后执行情况
- Java静态函数、父类、子类执行顺序
- java中执行子类的构造方法时,会不会先执行父类的构造方法
- java子类和父类的执行顺序
- java中子类继承父类程序执行顺序
- Java基础-父类-子类执行顺序