Наследяване на Kotlin (с примери)

В тази статия ще научите за наследяването. По-конкретно, какво е наследяване и как да го приложим в Kotlin (с помощта на примери).

Наследяването е една от ключовите характеристики на обектно-ориентираното програмиране. Позволява на потребителя да създаде нов клас (производен клас) от съществуващ клас (основен клас).

Полученият клас наследява всички функции от базовия клас и може да има свои собствени допълнителни функции.

Преди да влезете в подробности за наследяването на Kotlin, препоръчваме ви да проверите тези две статии:

  • Клас и предмети на Котлин
  • Котлин Първичен конструктор

Защо наследяване?

Да предположим, че във вашето приложение искате три знака - учител по математика , футболист и бизнесмен .

Тъй като всички герои са хора, те могат да ходят и да говорят. Те обаче притежават и някои специални умения. Учителят по математика може да преподава математика , футболистът може да играе футбол, а бизнесменът да управлява бизнес .

Можете индивидуално да създадете три класа, които могат да ходят, да говорят и да изпълняват своите специални умения.

Във всеки от класовете бихте копирали един и същ код за разходка и разговор за всеки герой.

Ако искате да добавите нова функция - яжте, трябва да приложите един и същ код за всеки знак. Това лесно може да стане податливо на грешки (при копиране) и дублиращи се кодове.

Би било много по-лесно, ако имахме Personклас с основни функции като говорене, разходка, хранене, сън и добавяне на специални умения към тези функции според нашите герои. Това се прави с помощта на наследяване.

Използването на наследството, сега не приложи същия код за walk(), talk()и eat()за всеки клас. Просто трябва да ги наследите .

И така, за MathTeacher(производен клас) вие наследявате всички характеристики на Person(основен клас) и добавяте нова функция teachMath(). По същия начин за Footballerкласа наследявате всички функции на Personкласа и добавяте нова функция playFootball()и т.н.

Това прави вашия код по-чист, разбираем и разширяем.

Важно е да запомните: Когато работите с наследяване, всеки производен клас трябва да отговаря на условието дали "е" основен клас или не. В горния пример, MathTeacher е a Person , Footballer е a Person . Не можете да имате нещо като, Businessman е a Business .

Наследство на Котлин

Нека се опитаме да приложим горната дискусия в код:

 отворен клас Person (възраст: Int) (// код за хранене, говорене, ходене) клас MathTeacher (възраст: Int): Person (възраст) (// други характеристики на учителя по математика) клас Футболист (възраст: Int): Person ( възраст) (// други характеристики на футболиста) клас Бизнесмен (възраст: Int): Човек (възраст) (// други характеристики на бизнесмена)

Тук Personе базов клас, както и класове MathTeacher, Footballerи Businessmanса получени от класа Person.

Забележете, ключовата дума openпреди основния клас Person,. Важно е.

По подразбиране класовете в Kotlin са окончателни. Ако сте запознати с Java, знаете, че крайният клас не може да бъде подкласиран. Използвайки отворената анотация за клас, компилаторът ви позволява да извличате нови класове от него.

Пример: Наследяване на Kotlin

 open class Person(age: Int, name: String) ( init ( println("My name is $name.") println("My age is $age") ) ) class MathTeacher(age: Int, name: String): Person(age, name) ( fun teachMaths() ( println("I teach in primary school.") ) ) class Footballer(age: Int, name: String): Person(age, name) ( fun playFootball() ( println("I play for LA Galaxy.") ) ) fun main(args: Array) ( val t1 = MathTeacher(25, "Jack") t1.teachMaths() println() val f1 = Footballer(29, "Christiano") f1.playFootball() )

Когато стартирате програмата, изходът ще бъде:

Моето име е Джак. Моята възраст е 25, аз преподавам в началното училище. Казвам се Кристиано. Моята възраст е 29 г. Играя за LA Galaxy.

Тук има два класа MathTeacherи Footballerса получени от Personкласа.

Първичният конструктор на Personкласа декларира две свойства: възраст и име и има блок за инициализация. Инициализиращият блок (и членовите функции) на базовия клас Personмогат да бъдат достъпни от обектите на производни класове ( MathTeacherи Footballer).

Извлечени класове MathTeacherи Footballerимат свои собствени функции teachMaths()и playFootball()съответно членове . Тези функции са достъпни само от обектите от съответния им клас.

Когато обектът t1 от MathTeacherкласа е създаден,

 val t1 = MathTeacher (25, "Jack")

Параметрите се предават на основния конструктор. В Kotlin initсе извиква блок, когато обектът е създаден. Тъй като MathTeacherе получен от Personклас, той търси блок за инициализатор в базовия клас (Person) и го изпълнява. Ако MathTeacherhas имаше init блок, компилаторът също би изпълнил init блока на производния клас.

След това teachMaths()функцията за обект t1се извиква с помощта на t1.teachMaths()оператор.

Програмата работи по подобен начин, когато се създава обект f1на Footballerкласа. Той изпълнява init блока на базовия клас. След това playFootball()методът на Footballerкласа се извиква с помощта на оператор f1.playFootball().

Важни бележки: Kotlin Inheritance

  • Ако класът има първичен конструктор, основата трябва да бъде инициализирана с помощта на параметрите на основния конструктор. В горната програма и двата производни класа имат два параметъра ageи nameи двата параметъра се инициализират в първичен конструктор в базовия клас.
    Ето още един пример:
     open class Person(age: Int, name: String) ( // some code ) class Footballer(age: Int, name: String, club: String): Person(age, name) ( init ( println("Football player $name of age $age and plays for $club.") ) fun playFootball() ( println("I am playing football.") ) ) fun main(args: Array) ( val f1 = Footballer(29, "Cristiano", "LA Galaxy") )  
    Тук първичният конструктор на производния клас има 3 параметъра, а основният клас има 2 параметъра. Имайте предвид, че и двата параметъра на базовия клас са инициализирани.
  • В случай, че няма първичен конструктор, всеки основен клас трябва да инициализира основата (използвайки супер ключова дума) или да делегира на друг конструктор, който прави това. Например,
     fun main(args: Array) ( val p1 = AuthLog("Bad Password") ) open class Log ( var data: String = "" var numberOfData = 0 constructor(_data: String) ( ) constructor(_data: String, _numberOfData: Int) ( data = _data numberOfData = _numberOfData println("$data: $numberOfData times") ) ) class AuthLog: Log ( constructor(_data: String): this("From AuthLog -> + $_data", 10) ( ) constructor(_data: String, _numberOfData: Int): super(_data, _numberOfData) ( ) )
    За да научите повече за това как работи тази програма, посетете Kotlin Secondary Constructor.

Отмяна на функциите и свойствата на членовете

If the base class and the derived class contains a member function (or property) with the same name, you can need to override the member function of the derived class using override keyword, and use open keyword for the member function of the base class.

Example: Overriding Member Function

 // Empty primary constructor open class Person() ( open fun displayAge(age: Int) ( println("My age is $age.") ) ) class Girl: Person() ( override fun displayAge(age: Int) ( println("My fake age is $(age - 5).") ) ) fun main(args: Array) ( val girl = Girl() girl.displayAge(31) )

When you run the program, the output will be:

 My fake age is 26.

Here, girl.displayAge(31) calls the displayAge() method of the derived class Girl.

You can override property of the base class in similar way.

Visit how Kotlin getters and setters work in Kotlin before you check the example below.

 // Empty primary constructor open class Person() ( open var age: Int = 0 get() = field set(value) ( field = value ) ) class Girl: Person() ( override var age: Int = 0 get() = field set(value) ( field = value - 5 ) ) fun main(args: Array) ( val girl = Girl() girl.age = 31 println("My fake age is $(girl.age).") )

When you run the program, the output will be:

 My fake age is 26.

As you can see, we have used override and open keywords for age property in derived class and base class respectively.

Calling Members of Base Class from Derived Class

Можете да извикате функции (и свойства за достъп) на базовия клас от производен клас, използвайки superключова дума. Ето как:

 open class Person() ( open fun displayAge(age: Int) ( println("My actual age is $age.") ) ) class Girl: Person() ( override fun displayAge(age: Int) ( // calling function of base class super.displayAge(age) println("My fake age is $(age - 5).") ) ) fun main(args: Array) ( val girl = Girl() girl.displayAge(31) )

Когато стартирате програмата, изходът ще бъде:

 Моята възраст е 31. Моята фалшива възраст е 26.

Интересни статии...