Menu
CoddyTech

构造函数链式调用

本课属于 Coddy Java 学习旅程的“面向对象编程”单元。第 23 课,共 87 课。

构造函数链式调用是指从一个构造函数中调用另一个构造函数的过程。当一个类有多个构造函数或涉及继承层次结构时,这种技巧有助于避免代码重复。

在同一个类中,你可以使用 this() 链式调用构造函数。这样,你可以有一个负责完成所有工作的“主”构造函数,而其他构造函数只需委托给它:

public class Rectangle {
    private int width;
    private int height;
    
    public Rectangle() {
        this(1, 1);  // 调用带两个参数的构造方法
    }
    
    public Rectangle(int size) {
        this(size, size);  // 创建一个正方形
    }
    
    public Rectangle(int width, int height) {
        this.width = width;
        this.height = height;
    }
}

在继承中,构造函数链会自动发生。创建子类对象时,Java 会先使用 super() 调用父类构造函数。如果你没有显式调用 super(),Java 会自动插入 super()(无参数版本):

public class Animal {
    private String name;
    
    public Animal(String name) {
        this.name = name;
        System.out.println("Animal constructor");
    }
}

public class Dog extends Animal {
    private String breed;
    
    public Dog(String name, String breed) {
        super(name);  // 必须放在第一行
        this.breed = breed;
        System.out.println("Dog constructor");
    }
}

创建 new Dog("Buddy", "Labrador") 时,会先打印 "Animal constructor",然后打印 "Dog constructor"。这样可以确保父类始终在子类添加自己的初始化设置之前正确完成初始化。

challenge icon

挑战

简单

我们来构建一个商品订购系统,演示同一个类内部以及继承层级中的构造函数链。你会看到,this() 如何在同一个类中链接构造函数,而 super() 如何链接到父类构造函数。

你将创建 3 个文件来组织代码:

  • Product.java:创建一个表示商店中任意商品的父类。它应包含:
    • 用于 name(String)和 price(double)的私有字段
    • 一个接收名称和价格的主构造函数,用于初始化字段,并打印:Product constructor: [name]
    • 另一个只接收名称的构造函数,它使用 this(name, 0.0) 链接到主构造函数,将默认价格设为 0.0
    • 用于访问字段的 getName() 和 getPrice() 方法
  • Electronics.java:创建一个继承 Product 并添加保修信息的子类:
    • 一个用于 warrantyYears(int)的私有字段
    • 一个接收名称、价格和保修年限的主构造函数,使用 super(name, price) 初始化父类,然后设置保修年限并打印:Electronics constructor: [warrantyYears] year warranty
    • 另一个只接收名称和价格的构造函数,它使用 this(name, price, 1) 链接到主构造函数,提供默认的 1 年保修期
    • 第三个只接收名称的构造函数,它使用 this(name, 0.0) 链接到第二个构造函数
    • 一个名为 getDetails() 的方法,返回:[name] - $[price] ([warrantyYears] year warranty)
  • Main.java:演示构造函数链的实际效果。你会收到 3 个输入:商品名称(String)、价格(double)和保修年限(int)。使用这 3 个参数创建一个 Electronics 对象,然后打印 getDetails() 的结果。

你会收到 3 个输入:商品名称、价格和保修年限。

在 getDetails() 中使用 String.format("%.2f", price) 将价格格式化为 2 位小数。仔细查看输出,你会看到构造函数消息按顺序出现,展示调用链如何从父类传递到子类!

亲手试试

import java.util.Scanner;

class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        
        // 读取输入
        String name = scanner.nextLine();
        double price = scanner.nextDouble();
        int warrantyYears = scanner.nextInt();
        
        // TODO:使用全部三个参数创建一个 Electronics 对象
        
        // TODO:打印 getDetails() 的结果
    }
}
quiz icon自我测试

这节课包含一个小测验。开始学习即可作答,并记录你的进度。

面向对象编程中的所有课

自己练习: Java 在线编译器