PAYATHON 2026

Java 中为什么要用 this(...) 调用其他构造函数?

数据阿明

使用 this(...) 调用同一个类的其他构造函数,可以复用初始化逻辑,让不同的创建方式遵循一致的初始化规则。并非每个类都需要这样写。

你的 Pay 示例还涉及 this,它是对当前对象的引用。this(...) 则用于构造函数委托。

为什么构造函数需要调用另一个构造函数?

题目中的 Foo 有两个构造函数:无参数版本提供默认值,带参数版本处理实际的初始化工作。

可以把它补充成下面这个例子:

class Foo {
    private final String bar;

    public Foo() {
        this("Some default value for bar");
    }

    public Foo(String bar) {
        if (bar == null) {
            throw new IllegalArgumentException("bar must not be null");
        }
        this.bar = bar;
    }

    public String getBar() {
        return bar;
    }
}

调用者可以选择:

Foo defaultFoo = new Foo();
Foo customFoo = new Foo("Custom value");

执行 new Foo() 时,无参数构造函数通过 this("Some default value for bar") 委托给带参数构造函数,由后者完成参数检查和字段赋值。

两个构造函数作用于同一个正在创建的对象,this(...) 不会额外创建一个 Foo 对象。

这样写还有一个好处:如果以后修改初始化规则,只需维护一处。如果每个构造函数都复制检查和赋值代码,修改时就容易遗漏某个入口。

有哪些实际使用场景?

一个常见场景是提供默认配置,同时允许调用者自定义。例如,下面的重试选项类允许省略重试次数。默认值 3 只是示例中自行约定的值:

class RetryOptions {
    private final int maxRetries;

    public RetryOptions() {
        this(3);
    }

    public RetryOptions(int maxRetries) {
        if (maxRetries < 0) {
            throw new IllegalArgumentException(
                "maxRetries must not be negative"
            );
        }
        this.maxRetries = maxRetries;
    }
}

调用者可以使用默认配置,也可以指定重试次数:

RetryOptions defaults = new RetryOptions();
RetryOptions custom = new RetryOptions(5);

默认配置和自定义配置都经过同一套检查。类似的安排也适用于带默认尺寸、默认名称或可选配置的对象。

题目中的注释还说明,无参数构造函数可以在被调用的构造函数完成后继续执行代码。如果它只负责提供默认参数,调用 this(...) 后也可以没有其他语句。

Pay 示例为什么不属于构造函数委托?

你的代码中只有一个 Pay 构造函数:

public Pay(double p)
{
    pay = p;
}

因此,当前没有另一个 Pay 构造函数可供委托,也没有必须引入 this(...) 的理由。

下面这句:

Overtime ot = new Overtime(x);

创建了另一个类的对象,并调用 Overtime 的构造函数。这与在 Pay 构造函数中使用 this(...) 调用其他 Pay 构造函数是不同的操作。

另外,原代码写的是:

myPay.calculatePayWithOvertime(MyPay);

Java 区分大小写。按照贴出的完整代码,MyPay 没有声明,需要改成 myPay 才能编译。

如何避免把 myPay 再传给自己?

如果这个方法的目的就是更新当前对象的 pay,可以删除参数,在方法内部使用 this:

public void calculatePayWithOvertime() {
    Overtime ot = new Overtime(this);
    pay = ot.getOvertimePay();
}

调用时写成:

Pay myPay = new Pay(100.0);
myPay.calculatePayWithOvertime();
System.out.println(myPay.getPay());

在这次调用中,方法里的 this 就是 myPay 所引用的对象,new Overtime(this) 把当前对象传给新建的 Overtime 对象。按示例中的计算规则,调用一次后结果为 150.0。

删除参数也缩小了方法的用途。原方法允许这样调用:

first.calculatePayWithOvertime(second);

它会读取 second 的 pay,计算后写入 first。如果确实需要这种行为,就不能直接改成只处理当前对象;如果本来就只打算处理当前对象,无参数版本更清楚。

这段计算还需要 Overtime 类吗?

如果 Overtime 的全部职责只是乘以 1.5,当前示例可以进一步简化为:

public void calculatePayWithOvertime() {
    pay = pay * 1.5;
}

这里访问的 pay 是当前对象的字段,也可以写成 this.pay。是否保留 Overtime 类,要看它是否还有其他独立职责。

这个方法会修改原来的 pay,因此连续调用两次会得到 100.0 × 1.5 × 1.5。如果业务要求每次都根据固定基础值计算,就需要保留基础值,或让方法返回计算结果而不覆盖它。

使用 this(…) 时要注意什么?

  • this(...) 用于构造函数之间的委托,不能在普通实例方法中用它重新初始化现有对象。
  • 目标构造函数由传入参数匹配;如果没有匹配的重载,代码无法编译。
  • 构造函数不能直接或间接循环委托,例如无参数构造函数调用带参数构造函数,后者又调用回无参数构造函数。
  • 上面的示例都将 this(...) 放在构造函数的第一条语句,与题目采用的写法一致。

备注:内容仅供参考。