杰瑞科技汇

Java构造方法如何调用其他构造方法?

核心概念

在 Java 中,一个类的构造方法可以调用同一个类中的另一个构造方法,这个过程被称为显式构造器调用(Explicit Constructor Invocation)

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

为什么需要这个功能? 主要目的是为了代码复用保证初始化逻辑的集中性,假设你有一个类,它的几个构造方法都需要执行一段相同的初始化代码(比如给某个成员变量赋一个默认值),你可以把这段公共代码放在一个“主构造方法”中,然后让其他构造方法都去调用它,从而避免代码重复。


语法

有两种语法形式:

  1. this 关键字调用:调用同一个类中的其他构造方法。

    • 语法:this(参数列表);
  2. super 关键字调用:调用直接父类的构造方法。

    Java构造方法如何调用其他构造方法?-图2
    (图片来源网络,侵删)
    • 语法:super(参数列表);

本篇重点讲解 this 的用法。


this() 调用规则

使用 this() 调用其他构造方法时,必须遵守以下非常重要的规则:

  1. 必须是第一条语句this() 语句必须是构造方法中的第一条可执行语句,在它之前,不能有任何其他代码(除了注释)。
  2. 不能形成闭环:不能出现两个或多个构造方法互相调用的情况,否则会导致栈溢出错误。
  3. 不能同时使用:在一个构造方法中,不能同时使用 this()super(),因为它们都必须是第一条语句,所以无法共存。

代码示例

下面通过一个经典的 Person 类来演示 this() 的用法。

假设 Person 类有 nameage 两个属性,我们希望:

  • 有一个无参构造方法,创建一个“匿名”且年龄为 0 的人。
  • 有一个只传 name 的构造方法,创建一个指定名字但年龄为 0 的人。
  • 有一个同时传 nameage 的构造方法。

不使用 this() 的写法(代码重复)

public class Person {
    private String name;
    private int age;
    // 构造方法1:无参
    public Person() {
        this.name = "Unknown"; // 重复的赋值逻辑
        this.age = 0;
        System.out.println("Person() called: " + this);
    }
    // 构造方法2:只传 name
    public Person(String name) {
        this.name = name;      // 重复的赋值逻辑
        this.age = 0;
        System.out.println("Person(String name) called: " + this);
    }
    // 构造方法3:传 name 和 age
    public Person(String name, int age) {
        this.name = name;
        this.age = age;
        System.out.println("Person(String name, int age) called: " + this);
    }
    @Override
    public String toString() {
        return "Person{" + "name='" + name + '\'' + ", age=" + age + '}';
    }
}

可以看到,构造方法1和构造方法2中都有 this.age = 0; 这行重复的代码。


使用 this() 的写法(代码复用)

我们可以将公共的初始化逻辑(设置默认年龄)放在参数最全的构造方法中,然后让其他构造方法通过 this() 来调用它。

public class Person {
    private String name;
    private int age;
    /**
     * 构造方法3:最完整的构造方法
     * 这个方法将作为其他构造方法的“基础”。
     */
    public Person(String name, int age) {
        this.name = name;
        this.age = age;
        System.out.println("Person(String name, int age) called: " + this);
    }
    /**
     * 构造方法2:只传 name
     * 它调用最全的构造方法,并传递默认的 age = 0。
     * 注意:this(...) 必须是第一条语句!
     */
    public Person(String name) {
        this(name, 0); // 调用 public Person(String name, int age)
        System.out.println("Person(String name) called: " + this);
    }
    /**
     * 构造方法1:无参
     * 它也调用最全的构造方法,传递默认的 name 和 age。
     */
    public Person() {
        this("Unknown", 0); // 调用 public Person(String name, int age)
        System.out.println("Person() called: " + this);
    }
    @Override
    public String toString() {
        return "Person{" + "name='" + name + '\'' + ", age=" + age + '}';
    }
    // 测试代码
    public static void main(String[] args) {
        System.out.println("--- Creating a person with no args ---");
        Person p1 = new Person();
        System.out.println("\n--- Creating a person with name only ---");
        Person p2 = new Person("Alice");
        System.out.println("\n--- Creating a person with name and age ---");
        Person p3 = new Person("Bob", 30);
    }
}

运行结果:

--- Creating a person with no args ---
Person(String name, int age) called: Person{name='Unknown', age=0}
Person() called: Person{name='Unknown', age=0}
--- Creating a person with name only ---
Person(String name, int age) called: Person{name='Alice', age=0}
Person(String name) called: Person{name='Alice', age=0}
--- Creating a person with name and age ---
Person(String name, int age) called: Person{name='Bob', age=30}

从结果可以看出:

  • new Person() 实际上先执行了 this("Unknown", 0),完成了成员变量的初始化。
  • new Person("Alice") 实际上先执行了 this("Alice", 0)
  • new Person("Bob", 30) 直接执行了它自己。

这样,公共的初始化逻辑就只写了一遍,代码更简洁、更易于维护。


super() 的关系(重要)

当一个类没有显式地用 this() 调用自身的其他构造方法时,它的构造方法默认会调用父类的无参构造方法 super()

下面的两段代码在效果上是完全相同的:

代码1(隐式调用 super()

public class Child extends Parent {
    public Child() {
        // 这里隐含了一句 super();
        System.out.println("Child's constructor");
    }
}

代码2(显式调用 super()

public class Child extends Parent {
    public Child() {
        super(); // 显式调用父类的无参构造方法
        System.out.println("Child's constructor");
    }
}

调用链: 当一个 new Child() 执行时,会发生以下事情:

  1. Child 的构造方法被调用。
  2. Child 构造方法中的 super()(无论显式还是隐式)被调用。
  3. Parent 的构造方法被调用。
  4. Parent 类没有父类,或者其构造方法也调用了 super(),这个过程会一直持续到 Object 类的构造方法。
  5. 然后从 Object 开始,一路返回,依次执行 ParentChild 构造方法中 super()this() 之后的代码。
特性 描述
目的 代码复用,避免在多个构造方法中重复编写相同的初始化代码。
语法 this(参数列表);
关键规则 this() 必须是构造方法中的第一条可执行语句
super() 的关系 this()super() 不能同时出现在一个构造方法中,因为它们都必须是第一条语句,如果构造方法中没有 this(),则默认有 super()
最佳实践 通常将参数最多的构造方法作为“主构造方法”,其他构造方法都通过 this() 来调用它,并将默认值作为参数传递过去。
分享:
扫描分享到社交APP
上一篇
下一篇