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: 6Un 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
}Desafío
FácilAnimal 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())
}
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
1Clases y objetos
Trabajar con archivosDefinir clasesConstructores primariosBloques init y validaciónConstructores secundariosRepaso - Tarjeta de biblioteca4Herencia
Clases abiertas y subclasesSobrescritura de miembrossuper y constructoresClases abstractasRepaso: directorio del personal2Propiedades y encapsulación
Accesores personalizadosModificadores de visibilidadSetters privadoslazy y lateinitRepaso: cuenta bancaria5Interfaces
Declaración de interfacesMétodos predeterminadosInterfaces múltiplesInterfaces como tiposRepaso: métodos de pago8Genéricos
Funciones genéricasClases genéricasRestricciones de tiposVariancia con in y outRepaso - Cola de prioridad11Proyecto: Gestión de biblioteca
Libros y miembrosPréstamo de librosPractica por tu cuenta: Playground de Kotlin