¿Cuáles son las semánticas de initialization de la class Kotlin?

No he podido encontrar nada en la definición de idioma que explica la initialization de una class en Kotlin.

import java.util.Properties fun main(args: Array<String>) { val out = MyClass() out.fn() } class MyClass { private val a = Properties() // 1 init { fn() } public fun fn() { println("Fn called. a = $a") } // private val a = Properties() // 2 } 

Los resultados de ejecutar este progtwig cambian dependiendo de si la propiedad se inicializa en (1) o en (2).

Me sorprende que el order de la statement sea relevante en el idioma y me gustaría entender las decisiones que hay detrás de esto. Mi expectativa sería que las properties se inicialicen antes de invocar el cuerpo constructor.

Mi expectativa sería que las properties se inicialicen antes de invocar el cuerpo constructor.

Bueno, el bloque de init no es un constructor . Es una construcción diferente que le permite realizar la initialization del object y estos [bloques de inicio] se realizan en el order de statement con los inicializadores de propiedad.

Los constructores son una ant bestia diferente y se realizan después de que todas las properties se inicializaron y se realizaron todos los bloques init. Mira el siguiente ejemplo:

 class A(val value: Int) { constructor(): this(0) { println("Constructor") } init { println("Init block") } } fun main(args: Array<String>) { val a = A() } 

La salida es:

 Init block Constructor 

Puedes colocar el bloque init donde quieras: antes del constructor o después de él; siempre se realizará antes del constructor de A (en este ejemplo, constructor secundario).

En pocas palabras: cuando se crea una instancia de una class, (casi) primero ejecuta el constructor de la class padre (si está presente), luego el constructor primario.

El constructor primario ejecuta el código declarado en el cuerpo de la class desde arriba hacia abajo. También los nombres estuvieron disponibles por la misma regla:

 class Foo(a: String = "might be first" val b: String = "second" + a) : Boo(a + b + "third"){ var c = a + "fourth" + b init {print("fifth: $c")} val d = "sixth" init {print("seventh: the end of the primary constructor"} } 

Si invoca un constructor secundario, entonces funciona después del primario, ya que está compuesto en la cadena (similar a invocar a los constructores originales).

  • Casilla de verificación "Incluir soporte de Kotlin" no en Android Studio 3.0 Canary 5
  • Dependencia circular cuando se comstack con Kotlin 1.1.2-4, pero no en 1.1.2-3
  • Motivo de la precedencia de los operadores con un tipo en el lado derecho
  • ¿Hay alguna manera de escribir una function de extensión que cambie el valor del object?
  • Configure Jackson para usar SNAKE_CASE "globalmente" en Spring Boot 2.0.0.M1
  • FragmentManager lanza IllegalArgumentException en Kotlin
  • ¿Cómo configurar Jacoco con Spek en un proyecto múltiple?
  • ¿Cómo puedo convertir InputStream en BufferInputStream en kotlin?
  • ¿Cómo puedo descartar la alerta después de hacer clic en el button Atrás?
  • Android muestra una advertencia aparentemente inofensiva cuando se reproduce audio?
  • Falló la inferencia del tipo de Kotlin: no coincide el tipo "matriz encontrada <*?>, Matriz obligatoria <*>?"