La clase sellada en Kotlin solo puede tener un constructor private . Eso significa que podemos llamar al constructor solo en sí mismo:
Las clases selladas no pueden tener constructores no privados (sus constructores son privados por defecto).
// `private` and `constructor()` are redundant. sealed class Expr private constructor()Pero, cuando utilizamos la clase sellada, una subclase debe heredar la clase sellada:
// Above Kotlin 1.1 data class Const(val number: Double) : Expr() data class Sum(val e1: Expr, val e2: Expr) : Expr() Como puede ver en el código anterior, el constructor private de la clase sellada se llama fuera de la clase sellada. Cuando se crea una instancia de la subclase, se llamará al constructor del padre (clase sellada) antes de llamar al propio constructor de la subclase. ¿Es solo una excepción a los modificadores de visibilidad?
https://kotlinlang.org/docs/reference/visibility-modifiers.html#classes-and-interfaces
Para miembros declarados dentro de una clase:
privatesignifica visible solo dentro de esta clase (incluidos todos sus miembros);
Considere el siguiente código:
open class A private constructor(var name: String){ class B : A("B") class C : A("C") }El código anterior se compila bien, ya que se llama al constructor dentro de la clase A. Si una clase D intenta heredar fuera de A, no se compilará.
class D : A("D") // Error: Cannot access '<init>': it is private in 'A'Como se menciona en la página Clase sellada en Kotlin ,
Una clase sellada puede tener subclases, pero todas ellas deben declararse en el mismo archivo que la propia clase sellada. (Antes de Kotlin 1.1, las reglas eran aún más estrictas: las clases tenían que anidarse dentro de la declaración de la clase sellada).
Parece que Kotlin relajó el requisito de clases anidadas solamente.
Entonces, el siguiente código funciona bien en 1.1+ pero fallaría en versiones anteriores:
sealed class A(var name: String) class B : A("B") class C : A("C")mientras que el siguiente código habría sido necesario en versiones anteriores a la 1.1, que respeta el constructor privado.
sealed class A (var name: String){ class B : A("B") class C : A("C") }Por lo tanto, permitir constructores privados de clases selladas fuera de la clase (pero dentro del mismo archivo) puede considerarse una mejora para hacer que el código sea más limpio.
Puede averiguar qué está sucediendo al observar el código de bytes generado (puede hacerlo yendo a Tools -> Kotlin -> Show Kotlin Bytecode y luego eligiendo Decompile en el panel que aparece). Descompilarlo a Java muestra este código para la clase Expr :
public abstract class Expr { private Expr() { } // $FF: synthetic method public Expr(DefaultConstructorMarker $constructor_marker) { this(); } } Entonces, hay un constructor no privado para la clase Expr generada, con un parámetro especial. Luego, como era de esperar, si observa el código de bytes descompilado de Const , por ejemplo, verá que llama a este constructor:
public final class Const extends Expr { public Const(double number) { super((DefaultConstructorMarker)null); this.number = number; } // other fields and methods ... } Todavía no puede subclasificar Expr de Kotlin, porque el compilador de Kotlin sabe que es una clase sellada de los metadatos en el archivo y lo respetará.
En cuanto al código del cliente Java, no puede acceder a este mismo constructor usted mismo porque DefaultConstructorMarker es un paquete privado en el paquete kotlin.jvm.internal en el que se encuentra, por lo que incluso si escribe la declaración de importación manualmente, el compilador no lo permitirá
Supongo que la visibilidad privada del paquete solo se puede aplicar en el momento de la compilación, y es por eso que el compilador de Kotlin puede generar el código de bytes correspondiente al fragmento anterior (aunque no estoy completamente seguro).