Освоюємо 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
}
Результат:
Мене звати Анатолій Непийвода і мій вік 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()
}
Результат:
Мене звати Віктор Кононенко і мій вік 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()
}
}