Перейти до вмісту

Освоюємо Kotlin/Успадкування

Матеріал з Вікіпідручника


В Kotlin, як і в інших ООП мовах, можна створювати ієрархію класів. Клас потомок може успадковувати властивості та функції батьківського(базового) класу. Всі класи в Kotlin є похідними класу Any і успадковують від нього функції equals(), hashCode() та toString().

Створення похідних класів

[ред.]

Розглянемо все на прикладі того, що є базовий клас Особа (Person) та похідні два класи Лікар (Doctor) та Пацієнт (Patient). Це логічно, оскільки доктор є певною особою і пацієнт є певною особою. Це так зване співвідношення is a.

По замовчуванню класи є фінальними і успадкування неможливе. Щоб дозволити спадкування необхідно використати при оголошенні класу ключове слово open:

open class Person // клас відкритий для успадкування

Для того, щоб клас був похідним від іншого класу, необхідно вказати його супертип(батьківський клас) після його назви та двохкрапок:

open class Person()
class Doctor:Person()
class Patient:Person()

В даному випадку оголошено два дочірніх класи Doctor та Patient на базі класу Person. При оголошенні базового класу, повинен бути викликаний його конструктор. У вищенаведеному випадку викликається пустий конструктор, але якщо б клас Person мав би властивості name та age, то оголошення класів нащадків виглядало б так:

open class Person(var name:String, var age:Int)
class Doctor (name:String, age:Int):Person(name, age)

Якщо похідний клас не має первинного конструктора, то вторинний конструктор повинен викликати конструктор базового класу використовуюче ключове слово super:

open class Person(var name:String, var age:Int)
class Doctor:Person{
    constructor(name:String, age:Int):super(name, age)
}

Клас нащадок успадковує властивості і функції від батьківського класу:

open class Person(var name:String, var age:Int){
    open fun introduce(){
        println ("Мене звати $name і мій вік $age років")
    }
}

class Doctor(name:String, age:Int, var specialization:String):Person (name, age){}

fun main(){
    val doctor=Doctor("Анатолій Непийвода", 56, "терапевт")
    doctor.introduce()   // через об'єкт Doctor відбувається доступ до функції introduce() класу Person
    println(doctor.name) // доступ до властивості name класу Person через об'єкт Doctor
}
Standard input or output Результат:
Мене звати Анатолій Непийвода і мій вік 56 років
Анатолій Непийвода

Заміщення властивостей та функцій

[ред.]

В Kotlin, ключове слово open вказує, що клас або його член (функція або властивість) можуть бути заміщені (overridden) у підкласі. Якщо ми заміщаємо певний член батьківського класу то вказуємо ключове слово override. По замовчуванню в Kotlin класи і їхні члени є final, що означає, що класи не можуть спадкуватись, а члени не можуть заміщатись, поки не будуть явно оголошені як відкриті (open).

open class Person(var name:String, var age:Int){
    open fun introduce(){
        println ("Мене звати $name і мій вік $age років")
    }
}

class Doctor(name:String, age:Int, var specialization:String):Person (name, age){
    override fun introduce() { // заміщаємо(перевизначаємо) батьківський метод
        super.introduce()  // викликаємо спочатку батьківську реалізацію функції
        println("   Я лікар $specialization")
    }
}

fun main(){
    val person=Person("Віктор Кононенко", 45)
    person.introduce()

    val doctor=Doctor("Анатолій Непийвода", 56, "терапевт")
    doctor.introduce()
}
Standard input or output Результат:
Мене звати Віктор Кононенко і мій вік 45 років
Мене звати Анатолій Непийвода і мій вік 56 років
   Я лікар терапевт

У вищенаведеному прикладі ми заміщаємо функцію introduce(). Щоб звернутися до батьківської реалізації функції ми використовуємо ключове слово super і пишемо super.introduce().

Відкриті властивості та функції успадковуються також як відкриті, якщо ми хочемо закрити можливість подальшого заміщення членів класу у похідних класах, то необхідно явно вказати ключове слово final. В наступному прикладі ми забороняємо заміщення функції introduce() в похідних класах за допомогою ключового слова final.

class Patient(name:String, age:Int, var ailment:String):Person (name, age){
    final override fun introduce() { 
        super.introduce()  
        println("   Я хворію на $ailment")
    }
}

Таким чином спадкоємці Patient не зможуть перевизначити власну функцію introduce().

Аналогічно до заміщення функцій, заміщаються і властивості.

Під час створення похідного класу, спочатку відбувається ініціалізація батьківського класу, а згодом похідного.

В Kotlin немає множинного успадкування класів. Тобто, неможливо спадкувати властивості і функції від кількох класів, але можливо реалізовувати кілька інтерфейсів. Якщо функція з одним і тим же ім'ям спадкується від класу та інтерфейсу, то компілятор заставить обов'язково замістити даний метод. При необхідності звернення до реалізації попередника необхідно вказати тип класу, що заміщається:

open class Person(){ //клас предок
    open fun introduce(){}
}

interface Doctor{    //реалізовуваний інтерфейс
    fun introduce() {}
}
class Dermatolog(n):Person(), Doctor{
    override fun introduce() {
        super<Person>.introduce()
        super<Doctor>.introduce()
    }
}