【问题标题】:Kotlin constructor properties and calling different superclass constructorsKotlin 构造函数属性和调用不同的超类构造函数
【发布时间】:2017-07-14 19:16:52
【问题描述】:

我想使用一个 kotlin 数据类作为例外,这似乎很好:

data class MyException(val extraData: Any) : RuntimeException()

我还希望能够在存在超类的情况下将cause 传递给超类。不幸的是,数据类在它们的主构造函数中只能有val/var,并且由于默认构造函数调用无参数RuntimeException()构造函数,似乎我根本无法做到这一点而不总是需要cause通过,存储为我的类中的一个字段,这是我不想要的。

我想要的是这样的:

data class MyException(val extraData: Any) : RuntimeException() {
    constructor(extraData: Any, cause: Throwable) : this(extraData) super(cause) {}
}

似乎即使我不使用数据类,我仍然无法使用方便的var/val构造函数助手,因为它们只能在必须选择哪个超级构造函数的主构造函数上使用。我能想到的最好的就是这个,非常冗长:

class MyException : RuntimeException {
    val extraData: Any

    constructor(extraData: Any) {
        this.extraData = extraData
    }

    constructor(extraData: Any, cause: Throwable) : super(cause) {
        this.extraData = extraData
    }
}

我错过了什么吗?真的没有办法基于重载的构造函数有条件地调用不同的超类构造函数并且仍然能够使用var/val 参数语法吗?如果是这样,为什么?有没有更好的方法来做这种事情?

【问题讨论】:

    标签: exception kotlin


    【解决方案1】:

    由于this(...)super(...) 都是构造函数中的第一条语句,因此您不能同时调用它。否则,您将获得编译时错误。

    如果任何类包含primary constructor,它们的secondary constructors 必须显式调用其主构造函数,因此您根本无法在辅助构造函数上调用额外的super(...)

    如果类具有主构造函数,则每个辅助构造函数都需要直接或通过另一个辅助构造函数间接委托给主构造函数。使用 this 关键字完成对同一类的另一个构造函数的委托

    但是还有另一种方法可以通过Throwable#initCause设置原因,例如:

    data class MyException(val extraData: Any) : RuntimeException() {
        constructor(extraData: Any, cause: Throwable) : this(extraData) {
            initCause(cause)
        }
    }
    

    ANDdata class 是为POJO 而设计的,而不是Exceptions。

    【讨论】:

      【解决方案2】:

      您想要的完全可以通过这样的常规课程实现:

      class MyException(val extraData: Any, cause: Throwable? = null) : RuntimeException(cause)
      

      在这里你有一个主构造函数,它总是接受extraData 并从中创建一个属性。它也接受异常原因,但它只将其传递给超类构造函数(注意第二个参数之前没有val)。它还利用了 Kotlin 中的默认参数,允许您不指定原因。

      不幸的是,您不能在您的情况下专门使用数据类,因为它们的主要构造函数不允许有常规参数。您还必须将原因声明为属性。数据类应该用于最简单的情况,而您有更复杂的情况。

      如果超类需要有条件地使用两个不同的构造函数进行初始化,那么您也必须在类中使用两个不同的构造函数。任何构造函数都必须将超类初始化委托给另一个构造函数,或者自己完成。它不能两者都做,因为这意味着超类被初始化了两次,这是没有意义的。此外,超类初始化和委托都发生在构造函数本身执行之前,因此您无法确定要执行哪一个的任何逻辑。

      你不能有一个主构造函数,因为它总是需要在存在时被委派给它。这意味着属性也必须显式声明,因为属性声明和初始化语法仅适用于主构造函数。

      【讨论】:

      • 谢谢。这和@holi-java 的答案都非常适合Exception 案例,因为异常允许空原因并正确处理它。无法调用不同的超级构造函数并且也无法使用var/val 参数的更普遍问题仍未得到解答。
      • @YonaAppletree 简而言之,这是不可能的。但如果您正在寻找解释,我已将其添加到答案中。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-02-01
      • 2019-01-10
      • 2013-07-19
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多