Modificadores de visibilidad o accesibilidad

Modificadores de visibilidad o accesibilidad en Kotlin

En Kotlin todo es público, a menos que definas que no debe serlo utilizando un modificador de visibilidad. Estos modificadores establecen la visibilidad o accesibilidad de los elementos a los que se aplican, que pueden ser clases, objetos, interfaces, constructores, funciones, propiedades y los métodos set de las propiedades (los métodos get tienen siempre la misma visibilidad que la propiedad).

En Kotlin existen cuatro modificadores de visibilidad: public (el predeterminado si no se utiliza ningún modificador explícito), private, protected e internal, que se pueden aplicar en declaraciones tanto a nivel superior (excepto protected) como dentro de una clase. Vamos a revisar ambos casos.

Al utilizar estos modificadores sobre declaraciones en el nivel superior de un archivo, es decir, directamente dentro de un paquete, cada uno de ellos tiene un efecto sobre la visibilidad de dicha declaración:
  • public: las declaraciones son visibles en todas partes (por defecto, por lo que suele ser redundante).
  • private: la declaración solo será visible dentro del archivo que contiene dicha declaración.
  • internal: visible dentro del mismo módulo (el conjunto de archivos compilados juntos).

Hay que tener en cuenta que para usar una declaración visible de nivel superior de otro paquete se debe importar (ver Importación de paquetes).

Un ejemplo de los modificadores de visibilidad a nivel superior:
// archivo: ejemplo.kt

package test

fun funcion1() {}   // public por defecto y visible en todas partes

private fun funcion2() { ... }   // visible en ejemplo.kt

internal fun funcion3() { ... }  // visible en el mismo módulo

public var nombre = "Pepe"  // visible en todas partes
    get() = field           // visible en todas partes igual que su propiedad
    private set(value) {    // visible en ejemplo.kt
        field = value
    }

internal val numero = 6    // visible en el mismo módulo

private class Clase1 { ... }   // visible en ejemplo.kt

Cuando estos modificadores se aplican a los miembros (funciones y propiedades) declarados dentro de una clase o interfaz (en la programación orientada a objetos se habla de encapsulamiento para hacer referencia al ocultamiento del estado, es decir, de los datos de un objeto de manera que solo se puedan cambiar mediante las operaciones definidas para ese objeto) funcionan así:
  • public: visible para cualquier cliente que pueda ver la clase.
  • private: visible solo dentro de esta clase (incluidos todos sus miembros).
  • protected: visible dentro de la clase y sus subclases (igual que private + visible también en subclases).
  • internal: visible para cualquier cliente dentro de este módulo que pueda ver la clase.
open class Base() {
    var a = 1                 // public por defecto
    private var b = 2         // visible solo en la clase Base
    protected open val c = 3  // visible en la clase Base y subclases
    internal val d = 4        // visible en el mismo módulo
    protected fun e() { }     // visible en la clase Base y subclases
}

class Derivada: Base() {
    // a, c, d y e() de la clase Base son visibles (public, protected e internal)
    // b no es visible (private)
    override val c = 9        // c es protected
}

class OtraClase(o: Base) {
    // o.b y o.c no son visibles (private y protected)
    // o.a y o.d son visibles (mismo módulo)
    // o.e() no es visible
}

fun main(args: Array<String>) {
    val base = Base()
    // base.a (public) es visible
    // base.d (internal) es visible
    // base.b (private) no es visible
    // base.c y base.e() no son visibles (protected)

    val derivada = Derivada()
    // derivada.c (protected) no es visible
}

Por otra parte, cuando un modificador de visibilidad se aplica a un constructor (por defecto public) se necesita explicitar la palabra constructor. Por ejemplo:
class Test(val a: Int) {
    // código
}
para cambiar su visibilidad se escribiría:
class Test private constructor(val a: Int) {
    // código
}

En el siguiente ejemplo se crea una clase (Calculo) con un método (cargarDatos) por defecto public, que llama a otro método (enterDatos) private de la misma clase para asignar un valor a dos propiedades de la clase también marcadas como private. Además también llama a otros dos métodos de la clase (sumar y restar) también marcados como private. Podemos comprobar que si llamamos a alguna propiedad o método marcados como private desde fuera de la clase se produce un error por imposibilidad de acceder a ese método.
class Calculo {
    private var valor1: Int = 0
    private var valor2: Int = 0

    private fun enterDatos (): Int {
        var input: Int?
        do {
            print("Introduce un valor entero: ")
            input = readLine()?.toIntOrNull()
            if (input == null) println("Valor no válido. Inténtalo de nuevo.")
        } while (input == null)
        return input // conversión implícita a Int
    }

    fun cargarDatos () {
        valor1 = enterDatos()
        valor2 = enterDatos()
        sumar()
        restar()
    }

    private fun sumar () {
        val suma = valor1 + valor2
        println ("$valor1 + $valor2 = $suma")
    }

    private fun restar () {
        val resta = valor1 - valor2
        println ("$valor1 - $valor2 = $resta")
    }
}

fun main () {
    val calculo1 = Calculo ()
    calculo1.cargarDatos()
    //calculo1.valor1 = 23 // ERROR: Cannot access 'valor1': it is private in 'Calculo'
    // calculo1.enterDatos() // ERROR: Cannot access 'enterDatos': it is private in 'Calculo'
}
Introduce un valor entero: 27
Introduce un valor entero: 16
27 + 16 = 43
27 - 16 = 11

Comentarios

Entradas populares

I/O: entrada y salida de datos en consola

Recursos gratis para aprender Kotlin

Lectura y escritura de archivos