杰瑞科技汇

Java构造函数如何调用其他构造函数?

this() 关键字

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

Java构造函数如何调用其他构造函数?-图1
(图片来源网络,侵删)
  • this(): 调用同一个类无参构造函数
  • this(参数列表): 调用同一个类有参构造函数

为什么需要调用其他构造函数?

想象一个场景,你有一个 Student 类,它有不同的创建方式:

  1. 创建一个新生,只需要提供姓名。
  2. 创建一个转学生,需要提供姓名、年龄和之前的学校。

这两种方式都需要初始化 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() 来调用它,从而避免代码重复。

Java构造函数如何调用其他构造函数?-图2
(图片来源网络,侵删)

语法规则

  1. 必须是第一条语句this() 调用必须是构造函数中的第一条可执行语句,这确保了对象在被使用之前,先通过另一个构造函数完成完整的初始化。
  2. 不能同时存在:在一个构造函数中,你不能同时调用 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

从输出可以看出:

  1. 当执行 new Student("Alice") 时,程序首先进入单参数构造函数,然后立即执行 this(name, 18, "Unknown"),跳转到三参数的主构造函数完成核心初始化,最后才执行单参数构造函数中 System.out.println... 语句。
  2. 这确保了无论通过哪个构造函数创建 Student 对象,name, age, 和 previousSchool 都能得到合理的初始化,避免了代码冗余。

super() 的关系

构造函数调用链(this()super())是理解 Java 对象创建过程的关键。

  1. 默认情况:如果你在子类的构造函数中没有显式地使用 this()super(),Java 编译器会自动在第一行插入一个对父类无参构造函数的调用,即 super()
  2. 显式调用:如果你使用了 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 中实现代码复用、保持构造函数清晰和简洁的最佳实践之一,它使得对象的初始化逻辑更加集中和易于维护。

分享:
扫描分享到社交APP
上一篇
下一篇