Переопределение членов
Часть раздела Объектно-ориентированное программирование путешествия по Kotlin на Coddy. Урок 18 из 57.
Подкласс может заменить унаследованный метод собственной версией. Суперкласс помечает метод как open, а подкласс повторно объявляет его с помощью 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"
}Внутри main:
println(Dog("Rex").sound())
println(Cat("Tom").sound())
println(Animal("Generic").sound())Вывод:
Woof
Meow
...Выбирается версия, которая выполняется, исходя из фактического класса объекта, даже если тип переменной является суперклассом. Код внутри суперкласса, вызывающий открытый метод, также получает версию подкласса:
open class Animal(val name: String) {
open fun sound() = "..."
fun speak() = "$name says ${sound()}"
}
class Dog(name: String) : Animal(name) {
override fun sound() = "Woof"
}Внутри main:
val pets: List<Animal> = listOf(Dog("Rex"), Animal("Generic"))
for (p in pets) println(p.speak())Вывод:
Rex says Woof
Generic says ...Свойства можно переопределять таким же образом: open val в суперклассе, override val в подклассе — как обычное свойство, свойство конструктора или вычисляемый геттер:
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"
}Внутри main:
for (s in listOf(Shape(), Triangle(), Polygon(6))) println("${s.name}: ${s.corners}")Вывод:
shape: 0
triangle: 3
6-gon: 6Член, отмеченный override, снова открыт, поэтому подкласс этого подкласса может переопределить его ещё раз; final override запрещает это. Член без open вообще нельзя переопределить, и подкласс не может объявить член с такой же сигнатурой:
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" // ошибка: 'sound' в 'Dog' является final
// fun sleep() = "nap" // ошибка: 'sleep' скрывает член суперкласса
}Задание
ЛегкоAnimal имеет legs() (4), sound() (...) и describe(), которая возвращает Rex has 4 legs and says Woof, используя legs() и sound(). Сделайте legs() и sound() переопределяемыми и завершите подклассы, переопределив только эти два метода: Dog говорит Woof, у Bird 2 ноги, и она говорит Tweet, а у Snake 0 ног, и она говорит Hiss. describe() остаётся таким, как есть, в Animal.
Предоставленный код считывает строки dog,Rex, bird,Pip, snake,Kaa или любой другой вид (обычный Animal), сохраняет животных в одном List<Animal> и выводит describe() для каждого.
Ваш код должен находиться в Animal.kt, Dog.kt, Bird.kt и Snake.kt. В Main.kt находится предоставленный код ввода/вывода, и его нельзя редактировать.
Попробуйте сами
fun main() {
// Предоставленный код ввода/вывода: оставьте его как есть
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())
}
В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.
Все уроки раздела Объектно-ориентированное программирование
1Классы и объекты
Работа с файламиОпределение классовПервичные конструкторыБлоки init и валидацияВторичные конструкторыПовторение — читательский билет4Наследование
Открытые классы и подклассыПереопределение членовsuper и конструкторыАбстрактные классыПовторение — каталог сотрудников7Специальные классы
Классы данныхКлассы перечисленийЗапечатанные иерархииequals, hashCode, toStringПовторение — трекер заказов10Паттерны проектирования. Часть 2
Делегирование с помощью byПаттерн декораторПаттерн строительПаттерн состояние2Свойства и инкапсуляция
Пользовательские аксессорыМодификаторы видимостиПриватные сеттерыlazy и lateinitПовторение — банковский счёт5Интерфейсы
Объявление интерфейсовМетоды по умолчаниюМножественные интерфейсыИнтерфейсы как типыПовторение — способы оплаты8Обобщения
Обобщённые функцииОбобщённые классыОграничения типовВариативность с in и outПовторение — очередь с приоритетом11Проект: Управление библиотекой
Книги и читателиВыдача книг3Объекты и компаньоны
Объявления объектовОбъекты-компаньоныКонстанты с constОбъектные выраженияПовторение — билетная касса6Полиморфизм
Динамическая диспетчеризацияПроверка типов и умные приведения типовwhen с типамиФункции-расширенияПовторение — смотритель зоопарка9Паттерны проектирования. Часть 1
Паттерн «Одиночка»Фабричный паттернПаттерн «Наблюдатель»Паттерн «Стратегия»Потренируйтесь самостоятельно: Песочница Kotlin