Error o característica: Kotlin permite cambiar 'val' a 'var' en inheritance

Empecé a explorar el idioma Kotlin. Estoy luchando con inheritance, var & val y efectos secundarios.

Si declaro un rasgo A con un val x AImpl x en AImpl , es posible anularlo como var (ver código a continuación). Sorprendentemente, el método print() en A se ve afectado por la reasignación de x aunque x sea ​​un valor en A ¿Es esto un error o una característica?

Código:

 trait A { fun print() { println("Ax = $x") } val x : Int; } class AImpl(x : Int) : A { override var x = x; // seems like x can be overriden as `var` } fun main(args: Array<String>) { val a = AImpl(2) a.print() // Ax = 2 ax = 3; // x can be changed // even though print() is defined in trait A // where x is val it prints x = 3 a.print() // Ax = 3 } 

Soy consciente del hecho de que si defino explícitamente a con tipo A no está permitido cambiar x :

 val a = AImpl(2) : A ax = 3 // ERROR: value x cannot be reassigned 

Pero como muestra el primer caso, la inheritance puede causar efectos secundarios que claramente no están previstos en A ¿Cómo protejo los valores de ser cambiados por inheritance?

Puedes hacer tu val final , es decir, prohibir anularlo en absoluto. Si define un val en una class, es final por defecto.

Además, si necesita anular un val con una var , pero no desea que el setter sea público, puede decir lo siguiente:

 override var x = 1 private set 

Anular un val con una var es una característica . Es equivalente a agregar un método set mientras que en la superclass solo había un método get. Y esto es bastante importante para implementar algunos patrones, como las interfaces de solo lectura.

No hay forma de "proteger" su val de ser anulado de una manera que permita cambiar la mutación de otra manera que no sea final , porque val no significa "reference inmutable", sino simplemente "propiedad de solo lectura". En otras palabras, cuando su rasgo A declara un val , significa que a través de una reference de tipo A el cliente no puede escribir este val , ninguna otra garantía prevista, o de hecho posible.

Los PS Semicolon son opcionales en Kotlin, no dude en omitirlos por completo

Consideraría esto una característica, ya que al cambiar val a var se imponen restricciones de uso más débiles y no se puede romper ningún código de superclass . Se puede observar una situación similar con los modificadores de visibilidad:

 trait A { protected fun print() { ... } } class AImpl: A { public override fun print() { ... } } 

En este ejemplo, las restricciones de visibilidad también se relajan por una subclass, aunque algunas personas consideran esta técnica como un antipatrón.

¿Cómo protejo los valores de ser cambiados por inheritance?

En kotlin puede definir explícitamente si cualquier subclass puede anular cualquier miembro de class particular utilizando open modificador open . En rasgos, sin embargo, todos los miembros están abiertos por defecto. La solución es replace el rasgo con la class, por lo que podrá controlar la inheritance:

 abstract class A { fun print() { ... } val x : Int = 2; } class AImpl(x : Int) : A() { override var x = x // comstacktion error } 
  • La actualización automática de la versión de la biblioteca para proyectos Gradle no está soportada actualmente. Actualice su build.gradle manualmente
  • En Kotlin, ¿por qué no se pasa el argumento pnetworkingeterminado después de asignar la function a una variable?
  • Kotlin: cómo acceder a las properties en el constructor
  • Enlace de datos de atributo personalizado Kotlin
  • ¿Cómo get una instancia delegada en Kotlin?
  • Hibernate OneToMany enlace incorrecto desde el padre
  • Crear nueva instancia de object Kotlin
  • ¿Cómo no emitir datos de Flowable para testings unitarias?
  • Diferencia entre Lock.withLock y sincronizado en Kotlin
  • Cómo detener el service de notificación en Android Oreo
  • Cómo usar jackson para deserializar las collections de Kotlin