【问题标题】:Kotlin - constructor default values and constructor overloadingKotlin - 构造函数默认值和构造函数重载
【发布时间】:2019-09-10 15:02:47
【问题描述】:

考虑以下代码:

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

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

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

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

【问题讨论】:

  • 您不需要bar,它只会使示例复杂化。有趣的。您仍然可以致电Foo("", true)。如果它警告辅助构造函数由于默认值而毫无意义,这似乎很有用。
  • 我的猜测是:因为它还没有实现 ;-) 从字节码的角度来看,我看到了 3 个构造函数……一个用于Foo(String, Boolean),一个合成的Foo(String, DefaultConstructorMarker),它使用默认值和Foo(String)...所以这是3个不同的构造函数...也许即将到来...另一方面我不知道我什么时候有过这样的星座...而且成本/收益比可能不是太好了……
  • 如果你使用'first'或'second'构造函数,你总是需要提供至少一个参数,即bar。在第二个构造函数中,您总是委托给主构造函数,并且您已经为它提供了一个默认值 false。从反编译的代码中读取,编译器似乎生成了一个合成方法,并在其中为所有签名提供了它们的值。所以不管你调用哪个构造函数,最终所有条件都满足了。
  • @series0ne 我的帖子能回答你的问题吗? :)
  • @WilliMentzel 是的 :)

标签: kotlin


【解决方案1】:

如果你看一下字节码,实际上生成了三个构造函数,正如 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 language specification 是这么说的:

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

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


我知道您的本意只是作为一个示例,但如果在现实世界中发生这种情况,您应该像Kotlin Language Documentation(第 76 页)所述那样避免这种情况:

如果你的对象有多个重载的构造函数 调用不同的超类构造函数并且不能简化为 具有默认参数值的单个构造函数,更喜欢替换 带有工厂函数的重载构造函数。

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

在这种情况下,创建后baz 将始终是什么(无需考虑重载解析规则)总是很清楚。

【讨论】:

    猜你喜欢
    • 2018-04-23
    • 1970-01-01
    • 1970-01-01
    • 2016-03-24
    • 2017-04-08
    • 1970-01-01
    • 2011-05-23
    • 2016-12-05
    相关资源
    最近更新 更多