Kotlin构造函数属性并调用不同的超类构造函数

时间:2017-07-14 19:16:53

标签: exception kotlin

我想使用kotlin数据类作为例外,看起来很好:

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

我还希望能够在一个存在的情况下将cause传递给超类。不幸的是,数据类只能在它们的主构造函数中有val / var,并且由于默认构造函数调用no-args 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参数语法?如果是这样,为什么?是否有更好的方法来做这种事情?

2 个答案:

答案 0 :(得分:2)

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

IF 任何类包含primary constructor,其secondary constructors必须明确调用其主要构造函数,因此您无法在辅助版上调用其他super(...)构造函数。

  

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

完成对同一类的另一个构造函数的委派

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

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

AND data class专为POJO而不是Exception而设计。

答案 1 :(得分:1)

对于像这样的常规课程,你想要的是完全可行的:

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

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

不幸的是,由于不允许主要构造函数具有常规参数,因此不能在您的情况下专门使用数据类。您还必须将原因声明为财产。数据类应该用于最简单的情况,而且你有一个更复杂的情况。

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

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