详解java中继承关系类加载顺序问题

 更新时间:2017年06月07日 11:48:37   作者:jake_fei  
这篇文章主要介绍了详解java中继承关系类加载顺序问题的相关资料,需要的朋友可以参考下

详解java中继承关系类加载顺序问题

实例代码:

/**
 * Created by fei on 2017/5/31.
 */
public class SonClass extends ParentClass{
  public SonClass(){
    System.out.println("SonClass's constructor");
  }
  { System.out.println("SonClass's block");}
  static {
    System.out.println("SonClass's static block ");
  }

  public static void main(String[] args) {
    System.out.println("------ main start ------ ");
    new SonClass();
    System.out.println("------ main end ------ ");
  }
}

class ParentClass{
  public ParentClass(){
    System.out.println("ParentClass's constructor");
  }
  { System.out.println("ParentClass's block");}
  static {
    System.out.println("ParentClass's static block ");
  }
}

运行结果:

ParentClass's static block 
SonClass's static block 
------ main start ------ 
ParentClass's block
ParentClass's constructor
SonClass's block
SonClass's constructor
------ main end ------ 

根据运行结果,一目了然,在执行 main 方法中 new SonClass() 之前,就在类加载之后执行了类中 static 代码块。然后再进入main方法,执行new操作,当然显而易见,在执行new子类操作的时候,是要先进行其父类的构造,即先执行父类的构造代码块(代码中只用大括号包裹的那段代码)以及构造函数 ,然后再执行子类的构造代码块以及构造函数。

修改一下代码,再来看看运行的结果:

/**
 * Created by fei on 2017/5/31.
 */
public class SonClass extends ParentClass{
  ParentClass parentClass;
  public SonClass(){
    System.out.println("1");
  }
  public SonClass(String name){
    System.out.println("2");
    this.name = name;
    parentClass = new ParentClass("FEI");
  }

  public static void main(String[] args) {
    System.out.println("------ main start ------ ");
    new SonClass("fei");
    System.out.println("------ main end ------ ");
  }
}

class ParentClass{
  String name ;
  public ParentClass(){
    System.out.println("3");
  }
  public ParentClass(String name){
    System.out.println("4");
    this.name = name ;
  }
}

运行的顺序是:

------ main start ------ 
3
2
4
------ main end ------ 

第一个规则:子类的构造过程中,必须调用其父类的构造方法。一个类,如果我们不写构造方法,那么编译器会帮我们加上一个默认的构造方法(就是没有参数的构造方法),但是如果你自己写了构造方法,那么编译器就不会给你添加了,所以有时候当你new一个子类对象的时候,肯定调用了子类的构造方法,但是如果在子类构造方法中我们并没有显示的调用基类的构造方法,如:super(); 这样就会调用父类没有参数的构造方法。

第二个规则:如果子类的构造方法中既没有显示的调用基类构造方法,而基类中又没有无参的构造方法,则编译出错,所以,通常我们需要显示的:super(参数列表),来调用父类有参数的构造函数,此时无参的构造函数就不会被调用。

总之,一句话:子类没有显示调用父类构造函数,不管子类构造函数是否带参数都默认调用父类无参的构造函数,若父类没有则编译出错。

还是两个类,我们再更改一下。

/**
 * Created by fei on 2017/5/31.
 */
public class SonClass extends ParentClass{
  private String name = "SonClass";

  public SonClass() {
    printName();
  }
  public void printName() {
    System.out.println("SonClass print name: " + name);
  }
  public static void main(String[] args){
    new SonClass();
  }
}

class ParentClass{
  private String name = "ParentClass";

  public ParentClass() {
    //System.out.println(this.getClass());
    printName();
  }
  public void printName() {
    System.out.println("ParentClass print name: " + name);
  }
}

看了上面的两个例子,最后这个例子就很容易被迷惑,可能有人会觉得运行结果是类似这样的:

ParentClass print name: ParentClass 
SonClass print name: SonClass

或者是:

ParentClass print name: SonClass
SonClass print name: SonClass

但真正的结果是这样的:

SonClass print name: null
SonClass print name: SonClass

为什么会这样,其实只要打开代码中父类构造器中的这句注释,就很容易理解了:System.out.println(this.getClass())
结果是:

class SonClass

没错,父类中的this引用是子类实例对象,所以在父类构造函数里调用的还是子类的printName()方法。具体原因也并我能十分肯定,我个人浅见,是因为虽然我们调用了父类的构造方法,但是我们并没有实例化出父类的实例对象,所以this还是指向的是子类的引用。

感谢阅读,希望能帮助到大家,谢谢大家对本站的支持!

相关文章

  • maven-assembly-plugin报红无法加载报错:Plugin ‘maven-assembly-plugin:‘ not found

    maven-assembly-plugin报红无法加载报错:Plugin ‘maven-assembly-plugin

    maven-assembly-plugin是一个常用的打包插件,但是在使用过程中经常会遇到各种报错,本文就来介绍一下maven-assembly-plugin报红无法加载报错,具有一定的参考价值
    2023-08-08
  • MyBatis-Plus实现条件查询的三种格式例举详解

    MyBatis-Plus实现条件查询的三种格式例举详解

    本文主要介绍了MyBatis-Plus三中条件查询格式的示例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2022-08-08
  • Java之多个线程顺序循环执行的几种实现

    Java之多个线程顺序循环执行的几种实现

    这篇文章主要介绍了Java之多个线程顺序循环执行的几种实现方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2023-09-09
  • spring boot打包成可执行jar包

    spring boot打包成可执行jar包

    本篇文章主要介绍了spring boot打包成可执行jar包,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-10-10
  • Presto支持Elasticsearch数据源配置详解

    Presto支持Elasticsearch数据源配置详解

    这篇文章主要为大家介绍了Presto支持Elasticsearch数据源配置详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-12-12
  • Java面试之动态规划与组合数

    Java面试之动态规划与组合数

    这篇文章主要介绍了Java面试之动态规划与组合数的相关知识,非常不错,具有一定的参考借鉴价值,需要的朋友可以参考下
    2019-09-09
  • Java如何实现双向链表功能

    Java如何实现双向链表功能

    双向链表也叫双链表,是链表的一种,它的每个数据结点中都有两个指针,分别指向直接后继和直接前驱。所以,从双向链表中的任意一个结点开始,都可以很方便地访问它的前驱结点和后继结点。一般我们都构造双向循环链表
    2021-11-11
  • java web实现邮箱激活与忘记密码

    java web实现邮箱激活与忘记密码

    这篇文章主要为大家详细介绍了java web实现邮箱激活与忘记密码、重置密码,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2019-02-02
  • java读写二进制文件的解决方法

    java读写二进制文件的解决方法

    本篇文章是对java读写二进制文件的方法进行了详细的分析介绍,需要的朋友参考下
    2013-05-05
  • java screen的配置详解及注意事项

    java screen的配置详解及注意事项

    这篇文章主要介绍了java screen的配置详解及注意事项的相关资料,需要的朋友可以参考下
    2017-07-07

最新评论