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

В этой статье вы узнаете о наследовании. Точнее, что такое наследование и как его реализовать в Kotlin (с помощью примеров).

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

Производный класс наследует все функции базового класса и может иметь собственные дополнительные функции.

Прежде чем вдаваться в подробности наследования Kotlin, мы рекомендуем вам проверить эти две статьи:

  • Класс и объекты Kotlin
  • Основной конструктор Котлина

Почему наследование?

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

Поскольку все персонажи - личности, они могут ходить и разговаривать. Однако у них также есть некоторые особые навыки. Учитель математики может преподавать математику , футболист - играть в футбол, а бизнесмен - вести бизнес .

Вы можете индивидуально создать три класса, которые могут ходить, разговаривать и проявлять особые навыки.

В каждом из классов вы будете копировать один и тот же код для ходьбы и разговора для каждого персонажа.

Если вы хотите добавить новую функцию - есть, вам нужно реализовать один и тот же код для каждого символа. Это может легко стать причиной ошибок (при копировании) и дублирования кодов.

Было бы намного проще, если бы у нас был Personкласс с базовыми функциями, такими как разговор, прогулка, еда, сон, и добавление специальных навыков к этим функциям в соответствии с нашими персонажами. Это делается с помощью наследования.

Использование наследования, теперь вы не реализуете один и тот же код walk(), talk()и eat()для каждого класса. Вам просто нужно унаследовать их.

Итак, для MathTeacher(производного класса) вы наследуете все функции Person(базового класса) и добавляете новую функцию teachMath(). Точно так же для Footballerкласса вы наследуете все функции Personкласса и добавляете новую функцию playFootball()и так далее.

Это делает ваш код более чистым, понятным и расширяемым.

Важно помнить: при работе с наследованием каждый производный класс должен удовлетворять условию, является ли он « базовым» классом или нет. В приведенном выше примере, MathTeacher является Person , Footballer является Person . У вас не может быть чего-то вроде, Businessman это Business .

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

Попробуем реализовать приведенное выше обсуждение в коде:

 open class Person (age: Int) (// код для еды, разговора, ходьбы) class MathTeacher (age: Int): Person (age) (// другие особенности учителя математики) class Footballer (age: Int): Person ( age) (// другие характеристики футболиста) class Бизнесмен (age: Int): Person (age) (// другие характеристики бизнесмена)

Здесь, Personявляется базовым классом, и классы MathTeacher, Footballerи Businessmanявляются производными от класса Person.

Обратите внимание, что ключевое слово openперед базовым классом Person. Это важно.

По умолчанию занятия в Котлине являются окончательными. Если вы знакомы с 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()соответственно. Эти функции доступны только из объектов соответствующего класса.

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

 val t1 = MathTeacher (25, «Джек»)

Параметры передаются основному конструктору. В Kotlin initблок вызывается при создании объекта. Поскольку, MathTeacherявляется производным от Personкласса, он ищет блок инициализатора в базовом классе (Person) и выполняет его. Если бы MathTeacherбыл блок init, компилятор также выполнил бы блок init производного класса.

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

Программа работает так же , когда объект f1из Footballerкласса создается. Он выполняет блок инициализации базового класса. Затем вызывается playFootball()метод Footballerкласса using f1.playFootball().

Важные примечания: наследование Kotlin

  • Если у класса есть первичный конструктор, основание должно быть инициализировано с использованием параметров первичного конструктора. В приведенной выше программе оба производных класса имеют два параметра 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 параметра. Обратите внимание, что оба параметра базового класса инициализируются.
  • В случае отсутствия основного конструктора каждый базовый класс должен инициализировать базу (используя ключевое слово super) или делегировать другому конструктору, который это делает. Например,
     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.

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