Menu
Coddy logo textTech

Sobrescritura de miembros

Parte de la sección Programación orientada a objetos del Journey de Kotlin de Coddy. Lección 18 de 57.

Una subclase puede reemplazar un método heredado con su propia versión. La superclase marca el método como open, y la subclase lo declara de nuevo con override:

open class Animal(val name: String) {
    open fun sound() = "..."
}
class Dog(name: String) : Animal(name) {
    override fun sound() = "Woof"
}
class Cat(name: String) : Animal(name) {
    override fun sound() = "Meow"
}

Dentro de main:

println(Dog("Rex").sound())
println(Cat("Tom").sound())
println(Animal("Generic").sound())

Salida:

Woof
Meow
...

La versión que se ejecuta se elige según la clase real del objeto, incluso cuando el tipo de la variable es la superclase. El código dentro de la superclase que llama a un método abierto también obtiene la versión de la subclase:

open class Animal(val name: String) {
    open fun sound() = "..."
    fun speak() = "$name says ${sound()}"
}
class Dog(name: String) : Animal(name) {
    override fun sound() = "Woof"
}

Dentro de main:

val pets: List<Animal> = listOf(Dog("Rex"), Animal("Generic"))
for (p in pets) println(p.speak())

Salida:

Rex says Woof
Generic says ...

Las propiedades se pueden sobrescribir de la misma manera: open val en la superclase, override val en la subclase, ya sea como una propiedad normal, una propiedad del constructor o un getter calculado:

open class Shape {
    open val name = "shape"
    open val corners = 0
}
class Triangle : Shape() {
    override val name = "triangle"
    override val corners = 3
}
class Polygon(override val corners: Int) : Shape() {
    override val name: String
        get() = "$corners-gon"
}

Dentro de main:

for (s in listOf(Shape(), Triangle(), Polygon(6))) println("${s.name}: ${s.corners}")

Salida:

shape: 0
triangle: 3
6-gon: 6

Un miembro marcado como override vuelve a estar abierto, por lo que una subclase de la subclase puede sobrescribirlo una vez más; final override lo impide. Un miembro sin open no se puede sobrescribir en absoluto, y una subclase no puede declarar un miembro con la misma firma:

open class Animal {
    open fun sound() = "..."
    fun sleep() = "zzz"
}
open class Dog : Animal() {
    final override fun sound() = "Woof"
}
class Puppy : Dog() {
    // override fun sound() = "Yip"   // error: 'sound' en 'Dog' es final
    // fun sleep() = "nap"            // error: 'sleep' oculta un miembro de la superclase
}
challenge icon

Desafío

Fácil

Animal tiene legs() (4), sound() (...) y describe(), que devuelve Rex has 4 legs and says Woof, construido a partir de legs() y sound(). Haz que legs() y sound() se puedan sobrescribir y completa las subclases sobrescribiendo únicamente esos dos métodos: Dog dice Woof, Bird tiene 2 patas y dice Tweet, y Snake tiene 0 patas y dice Hiss. describe() permanece tal como está en Animal.

El código proporcionado lee líneas dog,Rex, bird,Pip, snake,Kaa o cualquier otro tipo (un Animal simple), almacena los animales en una única List<Animal> e imprime describe() para cada uno.

Tu código va en Animal.kt, Dog.kt, Bird.kt y Snake.kt. Main.kt contiene el código de entrada/salida proporcionado y no se puede editar.

Pruébalo tú mismo

fun main() {
    // Código de entrada/salida suministrado: déjalo tal como está
    val input = generateSequence(::readLine).toList()
    val animals = mutableListOf<Animal>()
    for (line in input) {
        val (kind, name) = line.split(",")
        animals.add(when (kind) {
            "dog" -> Dog(name)
            "bird" -> Bird(name)
            "snake" -> Snake(name)
            else -> Animal(name)
        })
    }
    for (a in animals) println(a.describe())
}
quiz iconPonte a prueba

Esta lección incluye un breve cuestionario. Empieza la lección para responderlo y registrar tu progreso.

Todas las lecciones de Programación orientada a objetos

Practica por tu cuenta: Playground de Kotlin