Clases anidadas y clases internas

Clases anidadas y clases internas

Dentro de una clase se puede definir otra clase que se conoce como clase anidada (Nested Class), y como esta clase anidada es miembro de la clase exterior, se puede usar la notación del punto para acceder a la clase anidada y a sus miembros:
class Exterior {
    val a = "Fuera de la clase Anidada"

    class Anidada {
        val b = "Dentro de la clase Anidada."
        fun funAnidada() = "LLamada a la función desde la clase Anidada."
    }
}

fun main() {

    // acceso al miembro de la clase Exterior
    println(Exterior().a)

    // acceso al miembro de la clase Anidada
    println(Exterior.Anidada().b)

    // creación de un objeto de la clase Anidada
    val anidada = Exterior.Anidada()
    println(anidada.funAnidada())
}

Pero las clases anidadas no tienen acceso a las instancias de la clase externa. Por ejemplo, en el código anterior desde la clase 'Anidada' no podemos acceder a la propiedad 'a' de la clase 'Exterior'. Para resolver este problema debemos marcar la clase anidada con inner para crear una clase interior o interna (Inner Class) puesto que las clases internas conllevan una referencia a la clase externa y por tanto pueden acceder a sus miembros.
class Externa {
    val a = "Fuera de la clase Anidada"

    inner class Interna {
        fun funInterna() = a
    }
}

fun main() {
    println(Externa().Interna().funInterna())
}

A veces es posible que las variables o funciones de las clases externa e interna tengan el mismo nombre, y en estos casos usamos la palabra clave this@ para especificar desde qué clase desea acceder a esa variable o función (si no se especifica de esta manera, por defecto Kotlin verifica las variables y funciones en la clase interna antes de referirse a la clase externa).
class Externa {
    var numero = 0

    inner class Interna {
        private var numero = 1
        fun funInterna() {
            println(this@Externa.numero) // 0
            println(this@Interna.numero) // 1
        }
    }
}

fun main() {
    Externa().Interna().funInterna()
}

Aunque ahora no nos vamos a detener en esto, la clase interna puede ser anónima utilizando una expresión de objeto:
interface Empleado {
    fun hace()
}

fun main() {
    // creamos una instancia de la interfaz Empleado
    val programador: Empleado = object : Empleado {
        override fun hace() { // sobrescribe el método
            println("Ejemplo de clase interna anónima")
        }
    }
    programador.hace()
}

Comentarios

Entradas populares

I/O: entrada y salida de datos en consola

Recursos gratis para aprender Kotlin

Lectura y escritura de archivos