核心要点
在 Java 中,子类必须调用其父类的构造函数,这个调用是隐式或显式的,并且是构造子类对象过程中第一步必须完成的操作。

为什么必须调用父类构造函数?
一个子类对象不仅包含了子类自己定义的成员变量和方法,它也继承了父类的所有成员变量和方法,在创建子类对象时,系统首先需要确保父类的部分被正确地初始化,如果父类没有定义无参构造函数,而子类又没有显式调用父类的其他构造函数,编译器就会报错。
子类对象 = 父类部分 + 子类自己部分,初始化必须从最顶层的父类开始,自上而下进行。
如何调用?(两种方式)
隐式调用 (默认情况)
如果子类的构造函数没有使用 super 关键字显式地调用父类的某个构造函数,Java 编译器会自动在子类构造函数的第一行插入一条对父类无参构造函数的调用。
示例:

class Parent {
// 父类有一个无参构造函数
public Parent() {
System.out.println("Parent 的无参构造函数被调用");
}
}
class Child extends Parent {
// 子类的构造函数
public Child() {
// 这里虽然没有写 super(),但编译器会自动加上 super();
System.out.println("Child 的构造函数被调用");
}
}
public class Main {
public static void main(String[] args) {
Child child = new Child();
}
}
输出结果:
Parent 的无参构造函数被调用
Child 的构造函数被调用
过程分析:
new Child()执行,开始创建Child对象。Child的构造函数Child()被调用。- 在执行
Child()构造函数体内的代码之前,编译器自动插入了对super()的调用。 super()会去执行Parent类的无参构造函数Parent(),打印出 "Parent 的无参构造函数被调用"。- 父类构造执行完毕后,返回到
Child的构造函数,继续执行System.out.println(...),打印出 "Child 的构造函数被调用"。 Child对象创建完成。
显式调用 (使用 super 关键字)
当父类没有提供无参构造函数,或者你希望在子类构造函数中调用父类的有参构造函数以传递参数进行特定初始化时,就必须使用 super 关键字进行显式调用。
语法规则:
super(参数列表);

重要规则:
super(参数列表)必须是子类构造函数中的第一条可执行语句,这确保了父类在任何子类代码执行之前就被初始化。- 一个构造函数中不能同时调用
this()和super()。
示例 1:调用父类的有参构造函数
class Parent {
private String name;
// 父类只有有参构造函数,没有无参构造函数
public Parent(String name) {
this.name = name;
System.out.println("Parent 的有参构造函数被调用,name = " + name);
}
}
class Child extends Parent {
private int age;
// 子类构造函数,必须显式调用父类的构造函数
public Child(String name, int age) {
// super() 必须是第一行!调用父类的有参构造函数
super(name);
this.age = age;
System.out.println("Child 的有参构造函数被调用,age = " + age);
}
}
public class Main {
public static void main(String[] args) {
Child child = new Child("张三", 25);
}
}
输出结果:
Parent 的有参构造函数被调用,name = 张三
Child 的有参构造函数被调用,age = 25
过程分析:
new Child("张三", 25)执行。Child的构造函数Child(String name, int age)被调用。- 第一条语句
super(name)执行,它调用Parent类的构造函数Parent(String name),并传递 "张三"。 - 父类构造函数执行完毕后,返回到
Child的构造函数,继续执行this.age = age;和System.out.println(...)。
示例 2:父类没有无参构造函数时的错误情况
如果我们把上面的 Child 类构造函数改成不显式调用 super,会发生什么?
// ... Parent 类同上,只有 Parent(String name) ...
class Child extends Parent {
public Child(String name, int age) {
// 编译错误!
// this.age = age; // 错误:对父类构造函数的调用必须是构造函数中的第一条语句
}
}
编译错误:
error: no suitable constructor found in Parent
super();
^
constructor Parent.Parent(String) is not applicable
(actual and formal argument lists differ in length)
constructor Parent.Parent() is not applicable
(cannot access constructor Parent.Parent())
reason: no default constructor available in Parent
这个错误信息告诉我们:
- 编译器试图自动插入
super()来调用父类的无参构造函数。 - 但是在
Parent类中找不到无参构造函数Parent()。 - 编译失败。
super() 和 this() 的区别
| 特性 | super() |
this() |
|---|---|---|
| 含义 | 调用父类的构造函数。 | 调用本类的另一个构造函数。 |
| 作用 | 初始化对象继承自父类的部分。 | 在一个构造函数中调用另一个构造函数,以避免代码重复。 |
| 位置 | 必须在子类构造函数的第一行。 | 必须在构造函数的第一行。 |
| 共存 | 不能与 this() 在同一个构造函数中同时使用。 |
不能与 super() 在同一个构造函数中同时使用。 |
- 必须调用:子类构造函数在执行自己代码前,必须先调用父类的某个构造函数。
- 隐式 vs 显式:
- 如果父类有无参构造函数,子类构造函数可以不写
super(),编译器会自动添加super()。 - 如果父类没有无参构造函数,或者子类想调用父类的有参构造函数,则必须在子类构造函数的第一行显式地使用
super(参数列表)。
- 如果父类有无参构造函数,子类构造函数可以不写
- 第一原则:
super()或this()调用必须是构造函数中的第一条语句,这保证了初始化顺序的正确性(从父到子)。
理解并掌握父类构造函数的调用机制,是写出健壮、可维护的 Java 面向对象代码的基础。
