Java继承构造器使用过程解析

 更新时间:2019年12月16日 09:04:35   作者:sumerday  
这篇文章主要介绍了Java继承构造器使用过程解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下

这篇文章主要介绍了Java继承构造器使用过程解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下

初始化基类

前面提到,继承是子类对父类的拓展。《Thinking in Java》中提到下面一段话:

当创建一个导出类的对象时,该对象包含了一个基类的子对象。这个子对象与你用基类直接创建的对象是一样的。二者区别在于,后者来自于外部,而基类的子对象被包装在导出类的对象内部。

我们在创建子类对象时,调用了父类的构造器,甚至父类的父类构造器。我们知道,构造器用于创建对象,那么突然产生疑惑:关于创建一个子类对象时,是否会先创建父类对象?

经过查找资料,得出结论:

并没有。在创建子类对象时,会把父类的成员变量和方法加载进内存,既然要加载,便调用父类构造器看看这些数据是如何进行初始化的,仅此而已,并不是创建了父类的对象。

所以,可以看作,子类对象中包含着父类的子对象。我们知道,对象的初始化是至关重要的。那么,这个父类的子对象如何正确初始化呢?对了,就是接下来要说的:在构造器中调用基类构造器来执行初始化。
注意:子类并不能继承父类的构造器,只是单纯调用了基类构造器中的初始化代码。

默认构造器

先看一段简单的测试代码:

package com.my.pac13;
/*继承中的构造*/
public class Person {
  Person(){
    System.out.println("Person()");
  }
}
class Student extends Person{
  Student(){
    System.out.println("Student()");
  }
}
class PrimaryStudent extends Student{
  PrimaryStudent(){
    //super();
    System.out.println("PrimaryStudent()");
  }
  public static void main(String[] args) {
    //创建了PrimaryStudent对象
    new PrimaryStudent();
  }
}
/*
 Person()
 Student()
 PrimaryStudent()
*/

关于构造器,我们前面提到,任何没有显式构造器的类都存在着一个无参数的默认构造器。我们上面的例子在默认构造器中加入了打印输出,以便理解。

可以看到的是:

在创建PrimaryStudent时,他的直接父类Student和间接父类Person中的构造器都被调用了,而且可以看到,是"自上而下"的。
父类在子类构造器可以访问它之前,就已经完成了初始化的操作。

若子类没有显式调用父类的构造器,则自动调用父类的默认(无参)构造器。

带参数的构造器

前面的代码中,每个类都含有默认的构造器,创建子类对象时,是自上而下,且子类会默认调用父类的无参构造器。那么,假设父类正好没有无参构造器或者你正想调用父类的带参构造器,这时就需要我们的super关键字。(super关键字之后还会进行总结)

我们直接在原来的基础上稍作修改,并进行测试。

package com.my.pac13;
/*调用基类构造器是子类构造器中要做的第一件事*/
public class Person {
  //没有默认构造器
  Person(String name){
    System.out.println("Person()\t"+name);
  }
}
class Student extends Person{
  //也没有默认构造器,且用super显式调用
  Student(String n){
  //super关键字调用父类的构造器
    super(n);
    System.out.println("一参数Student\t"+n);
  }
  Student(String n,String m){
  //this关键字调用同一类中重载的构造器
    this(n);
    System.out.println("二参数student()\t"+m);
  }
}
class PrimaryStudent extends Student{
  //隐式调用父类构无参数构造器,但是父类没有,所以要用super显式调用
  PrimaryStudent(){
  //没有下面的语句会报错
    super("hello");
    System.out.println("PrimaryStudent()");
  }

}
class ExtendsTest{
  public static void main(String[] args) {
    new Person("the shy");
    System.out.println("***********");
    new Student("rookie");
    System.out.println("***********");
    new Student("the shy","rookie");
    System.out.println("***********");
    new PrimaryStudent();
    System.out.println("***********");
  }

}
/*
Person()  the shy
***********
Person()  rookie
一参数Student rookie
***********
Person()  the shy
一参数Student the shy
二参数student()  rookie
***********
Person()  hello
一参数Student hello
PrimaryStudent()
***********
 */
  • this是正在创建的对象,用于调用同一类中重载的构造器,可以参看我之前的文章:Java关键字之this。
  • super在调用构造器时,使用方法和this相似。(但super和this本身有本质的不同,super并不是一个对象的引用!!!)
  • super和this语句都必须出现在第一行,也就是说一个构造器中只能有其中之一。

子类调用父类构造器

无论是否使用super语句来调用父类构造器的初始化代码,子类构造器总是会事先调用父类构造器!这是一定要记住的!

子类构造器A在第一行显式使用super调用父类构造器B,格式super(参数列表),根据参数列表选择对应的父类构造器。

//父类
 Person(String name){
    System.out.println("Person()\t"+name);
  }
//子类
 Student(String n){
  //super关键字调用父类的构造器
    super(n);
    System.out.println("一参数Student\t"+n);
  }

子类构造器A先用this调用本类重载的构造器B,然后B调用父类构造器。

//父类
 Person(String name){
    System.out.println("Person()\t"+name);
  }
//子类
Student(String n){
  //super关键字调用父类的构造器
    super(n);
    System.out.println("一参数Student\t"+n);
  }
Student(String n,String m){
//this关键字调用同一类中重载的构造器
  this(n);
  System.out.println("二参数student()\t"+m);
}

子类构造器中没有super和this时,系统会隐式调用父类的无参构造器,要是没有无参的,那就报错。

//隐式调用父类构无参数构造器,但是父类没有,所以要用super显式调用
PrimaryStudent(){
//没有下面的语句会报错
  super("hello");
  System.out.println("PrimaryStudent()");
}

综上所述:

当调用子类构造器对子类对象进行初始化时,父类构造器总会在子类构造器之前执行。甚至,父类的父类会在父类之前执行……一直追溯到所有类的超类Object类的构造器。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。

相关文章

  • ElasticSearch启动成功却无法在浏览器访问问题解决办法

    ElasticSearch启动成功却无法在浏览器访问问题解决办法

    因工作的需要,要使用elasticsearch,安装完了,启动也成功了之后发现了问题,这篇文章主要给大家介绍了关于ElasticSearch启动成功却无法在浏览器访问问题的解决办法,需要的朋友可以参考下
    2024-10-10
  • Java序列化与反序列化

    Java序列化与反序列化

    这篇文章主要介绍了Java的序列化与反序列化,序列化把一个对象Java Object变为一个二进制字节序列byte[];反序列化就是把一个二进制字节序列byte[]变为Java对象Java Object。感兴趣的小伙伴可以参考阅读
    2023-04-04
  • MyBatis 引入映射器的方法

    MyBatis 引入映射器的方法

    本文通过实例代码给大家分享mybatis 引入映射器的方法,非常不错,具有参考借鉴价值,需要的朋友参考下吧
    2017-09-09
  • Spring AOP使用@Aspect注解 面向切面实现日志横切的操作

    Spring AOP使用@Aspect注解 面向切面实现日志横切的操作

    这篇文章主要介绍了Spring AOP使用@Aspect注解 面向切面实现日志横切的操作,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-06-06
  • Java根据前端传回的图片生成pdf并且加密码和水印

    Java根据前端传回的图片生成pdf并且加密码和水印

    这篇文章主要为大家详细介绍了java如何根据前端传回的png图片数组,后端加水印加密码生成pdf并返回给前端,感兴趣的小伙伴可以参考一下
    2025-01-01
  • 详解在spring boot中配置多个DispatcherServlet

    详解在spring boot中配置多个DispatcherServlet

    本篇文章主要介绍了详解在spring boot中配置多个DispatcherServlet,具有一定的参考价值,有兴趣的可以了解一下。
    2017-03-03
  • 如何给HttpServletRequest增加消息头

    如何给HttpServletRequest增加消息头

    这篇文章主要介绍了如何给HttpServletRequest增加消息头的实现方式,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-06-06
  • java Matcher匹配头尾截取替换字符串的案例

    java Matcher匹配头尾截取替换字符串的案例

    这篇文章主要介绍了java Matcher匹配头尾截取替换字符串的案例,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-12-12
  • Flutter实现文本组件、图标及按钮组件的代码

    Flutter实现文本组件、图标及按钮组件的代码

    这篇文章主要介绍了Flutter实现文本组件、图标及按钮组件的代码,本文给大家介绍的非常详细,具有一定的参考借鉴价值 ,需要的朋友可以参考下
    2019-07-07
  • Java 单例模式详细解释

    Java 单例模式详细解释

    这篇文章主要给大家介绍了关于Java中四种单例模式的相关资料,其中包括饿汉式、懒汉式、懒汉式(双重锁)及内部类等四种,分别给出了详细的示例代码和介绍,需要的朋友们下面来一起看看吧。
    2021-11-11

最新评论