Menu
Coddy logo textTech

Nadpisywanie składowych

Część sekcji Programowanie obiektowe ścieżki Kotlin w Coddy. Lekcja 18 z 57.

Podklasa może zastąpić odziedziczoną metodę własną wersją. Nadklasa oznacza metodę jako open, a podklasa deklaruje ją ponownie za pomocą 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"
}

Wewnątrz main:

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

Wynik:

Woof
Meow
...

Wersja, która jest uruchamiana, jest wybierana na podstawie rzeczywistej klasy obiektu, nawet gdy typ zmiennej jest typem nadklasy. Kod wewnątrz nadklasy, który wywołuje otwartą metodę, również otrzymuje wersję podklasy:

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

Wewnątrz main:

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

Wynik:

Rex says Woof
Generic says ...

Właściwości można nadpisywać w ten sam sposób: open val w nadklasie, override val w podklasie — jako zwykłą właściwość, właściwość konstruktora lub obliczany getter:

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"
}

Wewnątrz main:

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

Wynik:

shape: 0
triangle: 3
6-gon: 6

Element oznaczony jako override jest ponownie otwarty, więc podklasa tej podklasy może nadpisać go jeszcze raz; final override temu zapobiega. Elementu bez open nie można nadpisać, a podklasa nie może deklarować elementu z taką samą sygnaturą:

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"   // błąd: 'sound' w 'Dog' jest final
    // fun sleep() = "nap"            // błąd: 'sleep' przesłania składową klasy bazowej
}
challenge icon

Wyzwanie

Łatwy

Animal ma metody legs() (4), sound() (...) i describe(), która zwraca Rex has 4 legs and says Woof, utworzone z legs() i sound(). Spraw, aby metody legs() i sound() można było przesłaniać, i uzupełnij podklasy, przesłaniając tylko te dwie metody: Dog mówi Woof, Bird ma 2 nogi i mówi Tweet, a Snake ma 0 nóg i mówi Hiss. describe() pozostaje bez zmian w Animal.

Dostarczony kod odczytuje wiersze dog,Rex, bird,Pip, snake,Kaa lub dowolny inny rodzaj (zwykły Animal), przechowuje zwierzęta w jednej List<Animal> i wyświetla describe() dla każdego z nich.

Twój kod umieść w plikach Animal.kt, Dog.kt, Bird.kt i Snake.kt. Main.kt zawiera dostarczony kod wejścia/wyjścia i nie można go edytować.

Spróbuj swoich sił

fun main() {
    // Dostarczony kod wejścia/wyjścia: pozostaw go bez zmian
    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 iconSprawdź się

Ta lekcja zawiera krótki quiz. Zacznij lekcję, żeby na niego odpowiedzieć i śledzić swoje postępy.

Wszystkie lekcje w sekcji Programowanie obiektowe

Poćwicz samodzielnie: Edytor online Kotlin