首页 > 解决方案 > 为什么密封类的私有构造函数可以在子类中调用?

问题描述

Kotlin 中的密封类只能有private构造函数。这意味着我们只能调用构造函数本身:

密封类不允许有非私有的构造函数(它们的构造函数默认是私有的)。

// `private` and `constructor()` are redundant.
sealed class Expr private constructor()

但是,当我们使用密封类时,子类必须继承密封类:

// Above Kotlin 1.1
data class Const(val number: Double) : Expr()
data class Sum(val e1: Expr, val e2: Expr) : Expr()

正如您在上面的代码中看到的,密封类的private构造函数是在密封类本身之外调用的。子类实例化时,先调用父类(密封类)的构造函数,再调用子类自己的构造函数。它只是可见性修饰符的例外吗?

https://kotlinlang.org/docs/reference/visibility-modifiers.html#classes-and-interfaces

对于在类内声明的成员:private表示仅在该类内可见(包括其所有成员);

标签: kotlin

解决方案


考虑以下代码:

open class A private constructor(var name: String){
    class B : A("B")
    class C : A("C")
}

上面的代码编译得很好,因为构造函数是在类 A 内部调用的。如果类 D 试图从 A 外部继承,它将无法编译。

class D : A("D") // Error: Cannot access '<init>': it is private in 'A'

正如在 Kotlin 中的 Sealed 类页面中提到的,

密封类可以有子类,但所有子类都必须在与密封类本身相同的文件中声明。(在 Kotlin 1.1 之前,规则更加严格:类必须嵌套在密封类的声明中)。

似乎 kotlin 只放宽了嵌套类的要求。

因此,以下代码在 1.1+ 中可以正常工作,但在早期版本中会失败:

sealed class A(var name: String)
class B : A("B")
class C : A("C")

而在 1.1 之前的版本中将需要以下代码,它尊重私有构造函数。

sealed class A (var name: String){
    class B : A("B")
    class C : A("C")
}

因此,允许在类之外(但在同一个文件中)密封类的私有构造函数可以被认为是使代码更清晰的增强。


推荐阅读