首页 > 解决方案 > Kotlin - 构造函数默认值和构造函数重载

问题描述

考虑以下代码:

class Foo(val bar: String, val baz: Boolean = true) {
    constructor(bar: String) : this(bar, false)
}

如果不添加辅助构造函数,我可以调用Foo(""),因为第二个参数具有默认值。baz这将导致true.

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

为什么 Kotlin 不将其视为重复的构造函数签名,因为它们都可以使用相同的参数调用?

标签: kotlin

解决方案


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

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

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

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

这就是Kotlin 语言规范所说的:

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

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


我知道您打算将这仅作为一个示例,但是如果在现实世界中发生这种情况,则应该像Kotlin 语言文档(第 76 页)所述那样避免这种情况:

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

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

在这种情况下,它总是会立即清楚(无需考虑重载解析规则)baz创建后会发生什么。


推荐阅读