核心概念
在 Java 中,this 关键字除了可以引用当前对象的实例变量(字段)和实例方法外,还有一个非常重要的用途:在构造方法内部,调用同一个类的其他构造方法。

这种调用通常被称为显式构造器调用(Explicit Constructor Call)。
为什么需要用 this 调用构造方法?
主要目的是为了代码复用和保证初始化逻辑的集中性。
想象一个场景,你有一个类,它有多个构造方法,其中一个构造方法包含了复杂的初始化逻辑,另一个构造方法只是这个复杂构造方法的“简化版”,它只需要设置一些默认值,然后调用那个复杂的构造方法即可。
如果不使用 this 调用,你就不得不在多个构造方法中重复编写相同的初始化代码,这不仅违反了 DRY (Don't Repeat Yourself) 原则,也使得代码难以维护。

语法规则
使用 this 调用构造方法时,必须遵守以下严格规则:
- 位置:
this(...)调用必须是构造方法中的第一条可执行语句,在它之前,除了注释,不能有任何其他代码。 - 形式:
this后面必须紧跟括号 ,就像调用普通方法一样,括号内可以传递参数,用于匹配对应的构造方法。 - 互斥:在一个构造方法中,不能同时使用
this(...)调用和super(...)调用,因为子类的构造器在执行前必须先调用父类的构造器(隐式或显式),而this(...)调用会改变构造器执行的流程,Java 编译器禁止这种冲突。 - 链式调用:可以通过
this(...)形成一条构造方法链,从最简单的构造方法逐层向上调用,直到最复杂的那个构造方法。
代码示例
让我们通过一个 Person 类来演示 this 的用法。
场景描述
Person类有name和age两个属性。- 我们提供两个构造方法:
- 一个全参数构造方法:
Person(String name, int age) - 一个只提供
name的构造方法:Person(String name),在这种情况下,我们希望age默认为18。
- 一个全参数构造方法:
不使用 this 的方式(不推荐)
这种方式会导致代码重复,如果初始化逻辑变得更复杂,重复的代码会越来越多。
public class Person {
private String name;
private int age;
// 全参数构造方法
public Person(String name, int age) {
this.name = name;
this.age = age;
System.out.println("调用全参数构造方法");
}
// 只提供 name 的构造方法
public Person(String name) {
// 这里重复了 name 的赋值逻辑
this.name = name;
// 这里重复了 age 的默认值设置逻辑
this.age = 18;
System.out.println("调用单参数构造方法");
}
public void displayInfo() {
System.out.println("Name: " + name + ", Age: " + age);
}
public static void main(String[] args) {
Person p1 = new Person("Alice", 25);
p1.displayInfo(); // 输出: Name: Alice, Age: 25
Person p2 = new Person("Bob");
p2.displayInfo(); // 输出: Name: Bob, Age: 18
}
}
使用 this 的方式(推荐)
我们使用 this 来重构上面的代码,消除重复。

public class Person {
private String name;
private int age;
/**
* 1. 最复杂的构造方法,包含所有初始化逻辑。
* 这是其他构造方法最终都会调用的“主构造方法”。
*/
public Person(String name, int age) {
this.name = name;
this.age = age;
System.out.println("调用全参数构造方法");
}
/**
* 2. 简化版构造方法。
* 它只处理自己的参数,然后通过 this(name) 调用上面那个复杂的构造方法,
* 并传递默认的 age 值。
*/
public Person(String name) {
// this(...) 必须是第一条语句!
this(name, 18); // 调用同一个类的 Person(String name, int age) 构造方法
System.out.println("调用单参数构造方法");
}
public void displayInfo() {
System.out.println("Name: " + name + ", Age: " + age);
}
public static void main(String[] args) {
System.out.println("--- 创建 p1 ---");
Person p1 = new Person("Alice", 25);
p1.displayInfo();
/*
* 输出:
* --- 创建 p1 ---
* 调用全参数构造方法
* Name: Alice, Age: 25
*/
System.out.println("\n--- 创建 p2 ---");
Person p2 = new Person("Bob");
p2.displayInfo();
/*
* 输出:
* --- 创建 p2 ---
* 调用全参数构造方法
* 调用单参数构造方法
* Name: Bob, Age: 18
*/
}
}
代码分析
- 当执行
new Person("Bob")时,Java 会找到匹配的Person(String name)构造方法。 - 在这个构造方法中,第一行代码是
this(name, 18);,这会中断当前构造方法的执行流程,转而去调用Person(String name, int age)构造方法。 Person(String name, int age)构造方法执行完毕后,程序会返回到Person(String name)构造方法中,继续执行System.out.println(...)语句。- 创建
p2对象时,我们看到两行打印输出,这清晰地展示了构造方法的调用链。
最佳实践
- 设计一个“主构造方法”:将参数最多、逻辑最复杂的构造方法作为“主构造方法”,其他构造方法都通过
this(...)调用它。 - 避免构造方法链过长:虽然可以链式调用(如
this("A")调用this("A", 20),后者再调用this("A", 20, "USA")),但要确保链条清晰易懂,避免过于复杂的嵌套。 - 保持一致性:如果一个类有多个构造方法,尽量让它们都通过
this调用最终的那个“主构造方法”,这样可以保证所有对象的初始化逻辑都集中在一处,便于维护。
与 super() 的关系
this() 用于调用当前类的其他构造方法,而 super() 用于调用父类的构造方法。
它们遵循一个共同的规则:都必须是构造方法的第一条语句,因此不能同时出现在同一个构造方法中。
Java 的构造过程是这样的:
- 子类构造方法被调用。
- 如果子类构造方法没有显式调用
super(...),则会隐式地调用父类的无参构造方法super()。 - 父类的构造方法执行完毕。
- 然后回到子类构造方法,如果子类构造方法中有
this(...)调用,则执行它;否则,继续执行子类构造方法自身的剩余代码。
示例:
class Animal {
public Animal() {
System.out.println("Animal 的无参构造方法被调用");
}
}
class Dog extends Animal {
public Dog() {
// 隐式调用 super(),所以会先打印 Animal 的信息
System.out.println("Dog 的无参构造方法被调用");
}
public Dog(String name) {
// 显式调用 this(),它会先调用本类的无参构造方法 Dog()
this();
System.out.println("Dog 的带参构造方法被调用,name: " + name);
}
}
public class Main {
public static void main(String[] args) {
System.out.println("创建 Dog 对象 (无参):");
Dog d1 = new Dog();
System.out.println("\n创建 Dog 对象 (带参):");
Dog d2 = new Dog("Buddy");
}
}
输出:
创建 Dog 对象 (无参):
Animal 的无参构造方法被调用
Dog 的无参构造方法被调用
创建 Dog 对象 (带参):
Animal 的无参构造方法被调用
Dog 的无参构造方法被调用
Dog 的带参构造方法被调用, name: Buddy
这个例子清晰地展示了 super()(隐式)和 this() 在继承构造链中的调用顺序。
| 特性 | 描述 |
|---|---|
| 用途 | 在一个构造方法内部,调用同一个类的另一个构造方法,以实现代码复用。 |
| 语法 | this(arg1, arg2, ...); |
| 关键规则 | 必须是构造方法中的第一条可执行语句。 |
| 互斥性 | 不能与 super() 调用同时出现在同一个构造方法中。 |
| 优点 | 避免代码重复,集中初始化逻辑,使构造方法之间的关系更清晰。 |
