Al restringir la visibilidad de los detalles de implementación de una clase, nos aseguramos de poder cambiarlos sin el riesgo de romper el código que depende de la clase. Básicamente, los modificadores de visibilidad en Kotlin son similares a los de Java. Tiene los mismos modificadores public, protected y private. Pero la visibilidad predeterminada es diferente: si omite un modificador, la declaración se vuelve pública.
La visibilidad predeterminada en Java, paquete privado, no está presente en Kotlin. Kotlin usa paquetes solo como una forma de organizar el código en espacios de nombres; no los usa para el control de visibilidad. Como alternativa, Kotlin ofrece un nuevo modificador de visibilidad, internal, que significa “visible dentro de un módulo”. Un módulo es un conjunto de archivos Kotlin compilados juntos. Puede ser un módulo IntelliJ IDEA, un proyecto Eclipse, un proyecto Maven o Gradle, o un conjunto de archivos compilados con una invocación de una tarea Ant.
La ventaja de la visibilidad interna es que proporciona una encapsulación real para los detalles de implementación de su módulo. Con Java, la encapsulación se puede romper fácilmente, porque el código externo puede definir clases en los mismos paquetes utilizados por su código y, por lo tanto, obtener acceso a sus declaraciones privadas de paquetes.
Otra diferencia es que Kotlin permite el uso de visibilidad privada para declaraciones de nivel superior, incluidas clases, funciones y propiedades. Dichas declaraciones son visibles solo en el archivo donde se declaran. Esta es otra forma útil de ocultar los detalles de implementación de un subsistema.
- public: Por defecto y se puede ver en todos lados
- internal: Visible en el modulo
- protected: Visible en las subclases
- private: Visible solo en la clase y en el archivo.
Veamos un ejemplo. Cada línea de la función giveSpeech intenta violar las reglas de visibilidad. Se compila con un error.
internal open class TalkativeButton : Focusable {
private fun yell() = println("Hey!")
protected fun whisper() = println("Let's talk!")
}
fun TalkativeButton.giveSpeech() {
yell()
whisper()
}
Kotlin te prohíbe hacer referencia al tipo menos visible TalkativeButton (interno, en este caso) desde la función pública giveSpeech. Este es un caso de una regla general que requiere que todos los tipos usados en la lista de tipos base y parámetros de tipo de una clase, o la firma de un método, sean tan visibles como la clase o el método mismo. Esta regla garantiza que siempre tenga acceso a todos los tipos que pueda necesitar para invocar la función o ampliar una clase. Para resolver el problema, puede hacer que la función sea interna o que la clase sea pública.
Tenga en cuenta la diferencia de comportamiento del modificador protected en Java y en Kotlin. En Java, puede acceder a un miembro protegido desde el mismo paquete, pero Kotlin no lo permite. En Kotlin, las reglas de visibilidad son simples y un miembro protegido solo es visible en la clase y sus subclases. También tenga en cuenta que las funciones de extensión de una clase no obtienen acceso a sus miembros privados o protegidos.
Una diferencia más en las reglas de visibilidad entre Kotlin y Java es que una clase externa no ve miembros privados de sus clases internas (o anidadas) en Kotlin.