为什么可以在子类中调用密封类的私有构造函数?

时间:2019-02-10 06:21:44

标签: kotlin

Sealed class in 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构造函数在密封类本身之外被调用。实例化子类时,将在调用子类自己的构造函数之前调用parent(密封类)的构造函数。可见性修饰符只是例外吗?

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

  

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

2 个答案:

答案 0 :(得分:3)

您可以通过查看生成的字节码来了解正在发生的事情(可以通过转到Tools -> Kotlin -> Show Kotlin Bytecode,然后在出现的窗格中选择Decompile来完成此操作)。将其反编译为Java将显示Expr类的以下代码:

public abstract class Expr {
   private Expr() {
   }

   // $FF: synthetic method
   public Expr(DefaultConstructorMarker $constructor_marker) {
      this();
   }
}

因此 是用于生成的Expr类的非私有构造函数,带有特殊参数。然后,正如您所期望的,例如,如果查看Const的反编译字节码,您会发现它调用了此构造函数:

public final class Const extends Expr {
   public Const(double number) {
      super((DefaultConstructorMarker)null);
      this.number = number;
   }

   // other fields and methods ...
}

您仍然不能从Kotlin继承Expr,因为Kotlin编译器知道它是文件元数据中的密封类,因此会予以尊重。

对于Java客户端代码,您无法自己访问同一构造函数,因为DefaultConstructorMarker在其所在的kotlin.jvm.internal包中是包私有的,因此即使您写出导入手动声明,编译器将不允许。

我的猜测是,只有在编译时才能强制执行包私有的可见性,这就是为什么Kotlin编译器能够输出与上面的代码段相对应的字节码(虽然不确定)。

答案 1 :(得分:3)

考虑以下代码:

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'

Sealed class in Kotlin页所述,

  

密封类可以具有子类,但是所有子类必须与密封类本身在同一文件中声明。 (在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")
}

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

相关问题