Translate

jueves, 17 de enero de 2019

Propiedades y campos en Kotlin parte 2

Los campos no pueden ser declarados directamente en las clases de Kotlin. Sin embargo, cuando una
propiedad necesita un campo de respaldo, Kotlin lo proporciona automáticamente. Se puede hacer referencia a este campo de respaldo en los accesores utilizando el identificador de campo:


var counter = 0 // Nota: el inicializador asigna el campo de respaldo directamente
    valor ajustado) {
        if (valor> = 0) campo = valor
    }

El identificador de campo solo se puede utilizar en los accesores de la propiedad.

Se generará un campo de respaldo para una propiedad si utiliza la implementación predeterminada de al menos uno de los accesores, o si un descriptor de acceso personalizado lo hace referencia a través del identificador de campo.

Por ejemplo, en el siguiente caso no habrá ningún campo de respaldo:


val isEmpia: booleano
    get () = this.size == 0


Si desea hacer algo que no se ajuste a este esquema de "campo de respaldo implícito", siempre puede recurrir a una propiedad de respaldo:


private var _table: Map<String, Int>? = null
public val table: Map<String, Int>
    get() {
        if (_table == null) {
            _table = HashMap() // Type parameters are inferred
        }
        return _table ?: throw AssertionError("Set to null by another thread")
    }

En todos los aspectos, esto es lo mismo que en Java, ya que el acceso a las propiedades privadas con captadores y configuradores predeterminados está optimizado para que no se introduzca la sobrecarga de llamadas a funciones.

Las propiedades cuyo valor se conoce en tiempo de compilación se pueden marcar como constantes de tiempo de compilación utilizando el modificador const. Tales propiedades deben cumplir los siguientes requisitos:


  • Nivel superior, o miembro de una declaración de objeto o un objeto complementario.
  • Inicializado con un valor de tipo String o un tipo primitivo
  • Sin adjetivo personalizado


Tales propiedades pueden ser utilizadas en anotaciones:


const val SUBSYSTEM_DEPRECATED: String = "This subsystem is deprecated"
@Deprecated(SUBSYSTEM_DEPRECATED) fun foo() { ... }


Normalmente, las propiedades declaradas con un tipo no nulo deben inicializarse en el constructor. Sin embargo, bastante a menudo esto no es conveniente. Por ejemplo, las propiedades pueden inicializarse a través de la inyección de dependencia, o en el método de configuración de una prueba de unidad. En este caso, no puede proporcionar un inicializador que no sea nulo en el constructor, pero aún así desea evitar las comprobaciones nulas al hacer referencia a la propiedad dentro del cuerpo de una clase.

Para manejar este caso, puede marcar la propiedad con el modificador lateinit:


public class MyTest {
    lateinit var subject: TestSubject

    @SetUp fun setup() {
        subject = TestSubject()
    }

    @Test fun test() {
        subject.method()  // dereference directly
    }
}

El modificador se puede usar en las propiedades var declaradas dentro del cuerpo de una clase (no en el constructor principal, y solo cuando la propiedad no tiene un captador o definidor personalizado) y, desde Kotlin 1.2, para propiedades de nivel superior y variables locales . El tipo de propiedad o variable no debe ser nulo y no debe ser un tipo primitivo.

El acceso a una propiedad de inicio tardío antes de que se haya inicializado genera una excepción especial que identifica claramente la propiedad a la que se accede y el hecho de que no se ha inicializado.


Para verificar si ya se ha inicializado una var de lateinit, use .isInitialized en la referencia a esa propiedad:

if (foo::bar.isInitialized) {
    println(foo.bar)
}

Esta verificación solo está disponible para las propiedades que son accesibles léxicamente, es decir, declaradas en el mismo tipo o en uno de los tipos externos, o en el nivel superior en el mismo archivo.