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 }

执行结果:

22
34
17

你们答对了么?哈哈,现在来看一下代码具体执行情况:

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

2、执行B类的构造方法

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

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

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

显然这需要巩固一个知识点:当子类重写了父类的函数,那么子类的对象如果调用该函数,一定调用的是重写过后的函数。可以通过super关键字进行父类的重写函数的调用。

因为现在正在执行的是B类的构造方法,所以默认先会调用B类中的方法,如果B类中没有,才会调用其父类A中的方法

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

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

7、接着执行getValue()方法,首先在B类中找,但B类没有getValue()方法,所以就执行A类中的getValue()方法,A类中肯定是有的,要不然编译就不会通过

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

9、然后这个this指的到底是A类还是B类呢,答案是B类,因为现在是在执行B的构造方法,所以this指的应该是B类,即调用B类的setValue(int value)方法。

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

11、然后this.setValue(value)就执行完了,最后输出value,22

12、到这儿getValue()方法就执行完了,但是有一点需要注意,此时的value为22,但是getValue()的返回值确是11,因为在try{ }中已经return了,所以这个方法的返回值级已经保存下来了,是11,即使finally{ }里面又对value的值做出了改变,但是getValue()的返回值是不会变的。接着继续执行B类构造方法中的setValue(getValue() - 3);getValue()是11,所以B的setValue(int value)方法的参数就为8,接着又到了super.setValue(2 * value)

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

14、到这儿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。所以整个过程执行完后的输出结果是22、34、17。。。。。。

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

时间: 2024-11-06 07:14:23

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

Java中子类和父类的构造函数?

这篇文章总结了关于Java构造的常见??问题. 1)为什么创建一个子类对象要也需要调用父类的构造函数? class Super { String s; public Super(){ System.out.println("Super"); } } public class Sub extends Super { public Sub(){ System.out.println("Sub"); } public static void main(String[] a

java中子类继承父类程序执行顺序问题

Java中,new一个类的对象,类里面的静态代码块.非静态代码.无参构造方法.有参构造方法.类的一般方法等部分,它们的执行顺序相对来说比较简单,用程序也很容易验证.比如新建一个测试父类. public class FatherTest { private String name; FatherTest(){ System.out.println("--父类的无参构造函数--"); } FatherTest(String name){ this.name=name; System.out

[转]Java中子类调用父类构造方法的问题分析

在Java中,子类的构造过程中,必须调用其父类的构造函数,是因为有继承关系存在时,子类要把父类的内容继承下来,通过什么手段做到的? 答案如下:    当你new一个子类对象的时候,必须首先要new一个父类的对像出来,这个父类对象位于子类对象的内部,所以说,子类对象比父类对象大,子类对象里面包含了一个父类的对象,这是内存中真实的情况.构造方法是new一个对象的时候,必须要调的方法,这是规定,要new父类对象出来,那么肯定要调用其构造方法,所以: 第一个规则:子类的构造过程中,必须调用其父类的构造方

java中子类与父类中隐含的this引用的分析

/* 看一下下面的程序,看是否你的答案和运行的答案是否一致! */ class Parent{ public int x; public Parent p; public Parent(){} public Parent(int x){ this.x=x; p=this; } public void f(){ System.out.println("Parent::f()"); } public void g(){ System.out.println("Parent::g(

java中子类重写父类方法的思想本质

java语言中,在子类中定义与父类同返同名同参的方法将会出现"重写(覆写)",子类将屏蔽父类的相同方法,调用子类的方法将不会调用到父类的该方法. 许多初学者也许会被"覆写"一词迷惑,以为覆盖掉了父类的方法,其实这两种方法是同时独立存在的,只是子父类调用该方法的入口不一样,彼此互不干扰. 1 /* 2 需求:设计一个简单的java程序,证明子类重写父类方法的过程 3 思路: 1.创建父类对象,通过父类对象调用该方法 4 2.创建子类对象,通过父类对象调用该方法 5 3

java中子类覆盖父类方法所必须满足的条件

一.描述 子类重写(覆盖)父类的方法必须满足的条件: 1.父类中的方法在子类中必须可见,即子类继承了父类中的该方法(可以显式的使用super关键字来访问父类中的被重写的方法), 如果父类中的方法为private类型的,那么子类则无法继承,也无法覆盖. 2.子类和父类的方法必须是实例方法,如果父类是static方法而子类是实例方法,或者相反都会报错. 如果父类和子类都是static方法,那么子类隐藏父类的方法,而不是重写父类方法. 3.子类和父类的方法必须要具有相同的函数名称.参数列表,并且子类的

【Simple Java】关于JAVA中子类和父类的构造方法

本篇文章总结了一些关于Java构造方法的常见问题. 为什么创建了一个子类对象会调用其父类的构造方法 如下代码示例: package simplejava; class Super { String s; public Super() { System.out.println("Super"); } } class Sub extends Super { public Sub() { System.out.println("Sub"); } } public clas

Java中子类和父类的构造函数

这篇文章总结了关于Java构造的常见??问题. 1)为什么创建一个子类对象要也需要调用父类的构造函数? [java] view plain copy class Super { String s; public Super(){ System.out.println("Super"); } } public class Sub extends Super { public Sub(){ System.out.println("Sub"); } public stat

java中try{}catch{}和finally{}的执行顺序问题

 今天我给大家讲解一下java的的错误和异常处理机制以及相关异常的执行顺序问题.如有不足的地方,欢迎批评指正~ 1.首相简单介绍一下java中的错误(Error)和异常(Exception) 错误和异常的介绍: 在java.lang软件包中有一个java.lang.Throwable类,这个类是java中所有错误和异常的超类. 在java中错误和异常的继承主要有两个: 分别为Error和Exception 这两个. Error:         是java中所有错误类的父类,就是jvm出现错误,