Kotlin - 构造函数默认值和构造函数重载

ser*_*0ne 4 kotlin

考虑以下代码:

class Foo(val bar: String, val baz: Boolean = true) {
    constructor(bar: String) : this(bar, false)
}
Run Code Online (Sandbox Code Playgroud)

无需添加辅助构造函数,我就可以调用,Foo("")因为第二个参数具有默认值。这将导致baztrue

添加辅助构造函数后,我仍然可以调用Foo(""),除了现在bazfalse

为什么 Kotlin 不认为这是重复的构造函数签名,因为它们都可以用相同的参数调用?

Wil*_*zel 5

如果你看一下字节码,实际上生成了三个构造函数,正如 Roland 已经指出的那样。

public Foo(@NotNull String bar, boolean baz) { ... }
public Foo(String var1, boolean var2, int var3, DefaultConstructorMarker var4) { ... }
public Foo(@NotNull String bar) { ... }
Run Code Online (Sandbox Code Playgroud)

因此,没有重复的构造函数签名。现在有人可能会问 Kotlin 如何选择仅从调用站点判断的重载。

总体原理是将从重载候选中选择最具体的函数/构造函数。

Kotlin 语言规范是这样说的:

  • 对于每个候选,我们计算调用中未指定的默认参数的数量(即我们使用默认值的参数数量);

  • 具有最少数量的非指定默认参数的候选者是更具体的候选者;


我知道您希望这只是一个例子,但如果在现实世界中发生这样的事情,应该避免它,就像Kotlin 语言文档(第 76 页)所述:

如果您有一个具有多个重载构造函数的对象,这些构造函数不调用不同的超类构造函数,并且不能简化为具有默认参数值的单个构造函数,那么最好将重载的构造函数替换为工厂函数。

class Foo2(val bar: String, val baz: Boolean = true) {
    companion object {
        fun factoryCreate(s: String) = Foo2(s, false)
    }
}
Run Code Online (Sandbox Code Playgroud)

在这种情况下,创建之后的内容总是很清楚(无需考虑重载解析规则)baz