杰瑞科技汇

Java子类如何调用父类构造方法?

在 Java 中,子类构造方法在执行自己的构造逻辑之前,必须先(隐式或显式地)调用父类的构造方法,这个调用是为了确保父类中定义的成员变量和初始化代码能够被正确地初始化。

Java子类如何调用父类构造方法?-图1
(图片来源网络,侵删)

隐式调用 (Implicit Call)

当你没有在子类的构造方法中使用 super 关键字时,Java 编译器会自动在子类构造方法的第一行插入一个对父类无参构造方法的调用。

示例代码:

// 父类
class Animal {
    // 父类的无参构造方法
    public Animal() {
        System.out.println("Animal 的无参构造方法被调用");
    }
}
// 子类
class Dog extends Animal {
    // 子类的构造方法
    public Dog() {
        // 这里虽然没有写 super(),但编译器会自动加上 super();
        System.out.println("Dog 的构造方法被调用");
    }
}
public class Main {
    public static void main(String[] args) {
        Dog myDog = new Dog();
    }
}

输出结果:

Animal 的无参构造方法被调用
Dog 的构造方法被调用

执行流程分析:

Java子类如何调用父类构造方法?-图2
(图片来源网络,侵删)
  1. new Dog() 语句执行,JVM 为 Dog 对象分配内存。
  2. Dog 类的构造方法 Dog() 被调用。
  3. 在执行 Dog 构造方法体内的 System.out.println(...) 之前,编译器自动插入的 super() 代码被执行。
  4. super() 调用 Animal 类的无参构造方法 Animal()
  5. System.out.println("Animal 的无参构造方法被调用") 被执行。
  6. Animal() 构造方法执行完毕,返回到 Dog() 构造方法。
  7. 执行 Dog() 构造方法体内的 System.out.println("Dog 的构造方法被调用")
  8. Dog() 构造方法执行完毕,Dog 对象创建成功。

显式调用 (Explicit Call)

当你需要调用父类中带有参数的构造方法时,你必须使用 super 关键字进行显式调用super(...) 调用必须是子类构造方法中的第一条可执行语句

语法:

super(参数列表);

示例代码:

// 父类
class Person {
    private String name;
    // 父类的带参构造方法
    public Person(String name) {
        this.name = name;
        System.out.println("Person 的带参构造方法被调用,姓名是: " + this.name);
    }
}
// 子类
class Student extends Person {
    private int studentId;
    // 子类的构造方法,显式调用父类的带参构造方法
    public Student(String name, int studentId) {
        // super(name) 必须是第一条语句
        super(name); // 调用父类 Person 的带参构造方法
        this.studentId = studentId;
        System.out.println("Student 的构造方法被调用,学号是: " + this.studentId);
    }
}
public class Main {
    public static void main(String[] args) {
        Student myStudent = new Student("张三", 1001);
    }
}

输出结果:

Person 的带参构造方法被调用,姓名是: 张三
Student 的构造方法被调用,学号是: 1001

执行流程分析:

  1. new Student("张三", 1001) 语句执行。
  2. Student 类的构造方法 Student(String name, int studentId) 被调用。
  3. 该方法的第一条语句 super(name) 被执行,它调用了父类 PersonPerson(String name) 构造方法,并将 "张三" 作为参数传递过去。
  4. 父类构造方法 Person(String name) 执行,打印出 "Person 的带参构造方法被调用..."。
  5. 父类构造方法执行完毕,返回到子类构造方法。
  6. 子类构造方法继续执行 this.studentId = studentId;System.out.println(...)
  7. 子类构造方法执行完毕,Student 对象创建成功。

super()this() 的区别与联系

这是一个常见的面试点。super()this() 都只能在构造方法的第一行使用,因此它们不能同时出现

特性 super() this()
含义 调用父类的构造方法。 调用本类其他构造方法
目的 初始化从父类继承的成员变量。 在本类内部,用一个构造方法去调用另一个构造方法,避免代码重复。
示例 super("name"); this(name, age);

示例:this() 的使用

class Employee {
    private String name;
    private int age;
    // 构造方法1
    public Employee(String name, int age) {
        this.name = name;
        this.age = age;
        System.out.println("Employee 的两参构造方法被调用");
    }
    // 构造方法2
    public Employee(String name) {
        // 使用 this() 调用另一个构造方法,避免重复赋值 name
        this(name, 0); // 默认年龄为0
        System.out.println("Employee 的单参构造方法被调用");
    }
}
public class Main {
    public static void main(String[] args) {
        Employee emp1 = new Employee("李四", 30);
        System.out.println("---");
        Employee emp2 = new Employee("王五");
    }
}

输出结果:

Employee 的两参构造方法被调用
---
Employee 的两参构造方法被调用
Employee 的单参构造方法被调用

重要规则和注意事项

  1. 默认行为:如果子类构造方法没有显式调用 super(),并且父类没有提供无参构造方法,那么编译会报错

    • 原因:编译器试图为你插入 super(),但它找不到一个可匹配的无参父类构造方法。
    class Parent {
        // 父类没有无参构造方法
        public Parent(String s) {
            System.out.println("Parent's parametrized constructor");
        }
    }
    class Child extends Parent {
        public Child() {
            // 编译错误!因为 Parent 没有无参构造方法,
            // 而 super() 会被默认插入,但无法匹配。
            System.out.println("Child's constructor");
        }
    }
  2. 父类构造方法的不可见性:如果父类的构造方法是 private 的,子类将无法调用它,因此该子类将无法被实例化(除非父类有其他非 private 的构造方法)。

  3. 构造链:这个调用关系会一直向上追溯到 Object 类,因为所有 Java 类都直接或间接继承自 Object,任何一个对象的创建,最终都会调用 Object 类的构造方法。

    构造链示例: Grandpa -> Father -> Son new Son() -> Father() -> Grandpa() -> Object()

  • 子类必须先初始化父类,这是 Java 继承的基石。
  • 隐式调用super() (调用父类无参构造) 由编译器自动添加,当且仅当子类构造方法中没有显式的 super()this() 时。
  • 显式调用:使用 super(参数列表) 调用父类的指定构造方法,必须是子类构造方法的第一条语句。
  • super() vs this()super() 用于父类,this() 用于本类其他构造方法,两者不能共存于同一个构造方法的第一行。
  • 常见错误:忘记父类没有无参构造方法,导致子类编译失败。
分享:
扫描分享到社交APP
上一篇
下一篇