this() 关键字
在 Java 中,构造函数不能像普通方法那样被直接调用(new MyClass()),要在一个构造函数中调用同一个类的另一个构造函数,我们必须使用 this 关键字。

this(): 调用同一个类的无参构造函数。this(参数列表): 调用同一个类的有参构造函数。
为什么需要调用其他构造函数?
想象一个场景,你有一个 Student 类,它有不同的创建方式:
- 创建一个新生,只需要提供姓名。
- 创建一个转学生,需要提供姓名、年龄和之前的学校。
这两种方式都需要初始化 name 属性,如果没有构造函数调用,你可能会这样写:
// 不好的实践:代码重复
public class Student {
private String name;
private int age;
private String previousSchool;
// 构造函数1:只提供姓名
public Student(String name) {
this.name = name;
// age 和 previousSchool 保持默认值
}
// 构造函数2:提供姓名、年龄和学校
public Student(String name, int age, String previousSchool) {
this.name = name; // 重复的初始化代码
this.age = age;
this.previousSchool = previousSchool;
}
}
可以看到,this.name = name; 这行代码在两个构造函数中重复了。name 的初始化逻辑变得更复杂,这种重复会导致维护困难。
如何正确地调用构造函数?
我们可以将通用的初始化逻辑放在一个“主”构造函数中(通常是参数最多的那个),然后让其他构造函数通过 this() 来调用它,从而避免代码重复。

语法规则
- 必须是第一条语句:
this()调用必须是构造函数中的第一条可执行语句,这确保了对象在被使用之前,先通过另一个构造函数完成完整的初始化。 - 不能同时存在:在一个构造函数中,你不能同时调用
this()和super()(调用父类构造函数),因为super()也必须是第一条语句,两者会产生冲突。
代码示例
我们用 this() 来优化上面的 Student 类。
public class Student {
private String name;
private int age;
private String previousSchool;
/**
* 构造函数3:主构造函数(最完整的版本)
* 包含所有必要的初始化逻辑。
*/
public Student(String name, int age, String previousSchool) {
System.out.println("调用主构造函数 (name, age, school)");
this.name = name;
this.age = age;
this.previousSchool = previousSchool;
}
/**
* 构造函数1:只提供姓名
* 它通过 this() 调用主构造函数,并为其他参数提供默认值。
*/
public Student(String name) {
// this() 必须是第一条语句
this(name, 18, "Unknown"); // 调用上面的三参数构造函数
System.out.println("调用单参数构造函数");
}
/**
* 构造函数2:提供姓名和年龄
* 它也通过 this() 调用主构造函数,并为学校提供默认值。
*/
public Student(String name, int age) {
// this() 必须是第一条语句
this(name, age, "No Previous School"); // 调用上面的三参数构造函数
System.out.println("调用双参数构造函数");
}
// 打印学生信息的方法
public void printInfo() {
System.out.println("Name: " + name + ", Age: " + age + ", School: " + previousSchool);
}
public static void main(String[] args) {
System.out.println("--- 创建新生 ---");
Student freshman = new Student("Alice");
freshman.printInfo();
System.out.println("\n--- 创建转学生 ---");
Student transferStudent = new Student("Bob", 20, "XYZ University");
transferStudent.printInfo();
System.out.println("\n--- 创建只提供年龄的学生 ---");
Student studentWithAge = new Student("Charlie", 22);
studentWithAge.printInfo();
}
}
输出结果分析
--- 创建新生 --- 调用主构造函数 (name, age, school) 调用单参数构造函数 Name: Alice, Age: 18, School: Unknown --- 创建转学生 --- 调用主构造函数 (name, age, school) Name: Bob, Age: 20, School: XYZ University --- 创建只提供年龄的学生 --- 调用主构造函数 (name, age, school) 调用双参数构造函数 Name: Charlie, Age: 22, School: No Previous School
从输出可以看出:
- 当执行
new Student("Alice")时,程序首先进入单参数构造函数,然后立即执行this(name, 18, "Unknown"),跳转到三参数的主构造函数完成核心初始化,最后才执行单参数构造函数中System.out.println...语句。 - 这确保了无论通过哪个构造函数创建
Student对象,name,age, 和previousSchool都能得到合理的初始化,避免了代码冗余。
与 super() 的关系
构造函数调用链(this() 和 super())是理解 Java 对象创建过程的关键。
- 默认情况:如果你在子类的构造函数中没有显式地使用
this()或super(),Java 编译器会自动在第一行插入一个对父类无参构造函数的调用,即super()。 - 显式调用:如果你使用了
this(),就不能再使用super(),反之亦然。
示例:继承关系中的构造函数调用
class Person {
private String species;
public Person() {
this.species = "Homo Sapiens";
System.out.println("Person: 无参构造函数被调用");
}
}
class Student extends Person {
private String name;
// 构造函数1
public Student() {
// super() 会被隐式调用,等同于 super();
System.out.println("Student: 无参构造函数被调用");
}
// 构造函数2
public Student(String name) {
// super() 会被隐式调用
this.name = name;
System.out.println("Student: 单参数构造函数被调用");
}
// 构造函数3:显式调用父类构造函数
public Student(String name, int age) {
super("Humanoid"); // 显式调用父类的有参构造函数
this.name = name;
System.out.println("Student: 双参数构造函数被调用");
}
}
public class Main {
public static void main(String[] args) {
System.out.println("--- 创建 Student 对象 1 ---");
Student s1 = new Student();
// 输出:
// Person: 无参构造函数被调用
// Student: 无参构造函数被调用
System.out.println("\n--- 创建 Student 对象 2 ---");
Student s2 = new Student("David");
// 输出:
// Person: 无参构造函数被调用
// Student: 单参数构造函数被调用
System.out.println("\n--- 创建 Student 对象 3 ---");
Student s3 = new Student("Eve", 25);
// 输出:
// Person: 有参构造函数被调用 (假设Person有这个构造函数)
// Student: 双参数构造函数被调用
}
}
| 特性 | 描述 | 语法 | 规则 |
|---|---|---|---|
| 构造函数调用 | 在一个构造函数中调用同一个类的另一个构造函数。 | this() 或 this(参数列表) |
必须是构造函数中的第一条语句。 不能与 super() 同时出现在同一个构造函数中。 |
| 父类构造调用 | 在子类构造函数中调用父类的构造函数。 | super() 或 super(参数列表) |
如果没有显式调用,编译器会自动添加一个无参的 super()。也必须是第一条语句。 |
使用 this() 调用构造函数是 Java 中实现代码复用、保持构造函数清晰和简洁的最佳实践之一,它使得对象的初始化逻辑更加集中和易于维护。
