В 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 }
Заміщення властивостей та функцій В 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() }
У вищенаведеному прикладі ми заміщаємо функцію 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()
Клас Any Клас Any є предком (суперкласом) для усіх об'єктів в Kotlin. Це аналог класу Object у Java. Цей клас визначає функції equals(), hashCode() та toString(). equals() відповідає за порівняння об'єктів, hashCode() - за генерацію унікального ідентифікатора об'єкту, toString() - відповідає за представлення об'єкта у виді String, виклик цієї функції відбувається при виклику функції println() з вказанням назви об'єкта як аргумента. Всі функції можна замістити і надати власну реалізацію, якщо реалізація по замовчуванню вам не підходить. Детальніше про клас Any і його базові функції можна подивитись у цьому відео.