English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية

Основной курс Kotlin

Kotlin управление потоком

Функции в Kotlin

Строки в Kotlin

Kotlin面向对象(OOP)

Ингерит в Kotlin

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

Inheritance is one of the key features of object-oriented programming. It allows users to create a new class (derived class) from an existing class (base class).

Derived classes inherit all the functions of the base class and can have their own other functions.

Before a detailed introduction to Kotlin inheritance, it is recommended that you read the following two articles:

Why inheritance?

Suppose that in your application you need three roles - onemath teacher(MathTeacher), afootball player(Footballer) and abusinessman (Businessman).

Since all roles are people, they can walk and talk. However, they also have some special skills. A math teacher canteach mathematics (teachMath), a football player canplay football(playFootball), a businessman canRun business (runBusiness).

You can create three separate classes that can walk, talk, and perform their special skills.

In each class, you will copy the same walking and talking code for each role.

If you need to add a new feature - eat (eating), you need to implement the same code for each role. This can easily lead to errors (when copying) and duplicate code.

If we have a Person class with basic functions, for example, walk, eat, sleep, and add special skills for these functions according to our role, it would be much easier. This is done through inheritance.

With inheritance, you do not need to implement the same walk(), talk(), and eat() code for each class. You just needInheritanceThat's all.

Therefore, for MathTeacher (derived class), you can inherit all the functions of Person (base class) and add a new function teachingMath(). Similarly, for Footballer class, you inherit all the functions of Person class and add a new function playFootball(), and so on.

This makes your code more concise, understandable, and scalable.

It is important to remember:When dealing with inheritance, each derived class should meet the conditions of whether it is a 'base' class. In the above example, MathTeacher is a Person (person), Footballer is a Person (person). You cannot think that 'businessman (Businessman) is business (Business)'.

Kotlin inheritance

Let's try to implement the above discussion in the code:

open class Person(age: Int) {
    //eating, talking, walking code
{}
class MathTeacher(age: Int): Person(age) {
    // Другие характеристики математического учителя
{}
class Footballer(age: Int): Person(age) {
    // Другие характеристики футболиста
{}
class Businessman(age: Int): Person(age) {
    // Другие характеристики бизнесмена
{}

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

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

По умолчанию, классы в Kotlin являются конечными. Если вы знакомы с Java, то вы знаете, что конечные классы не могут быть наследованы. Используя аннотацию, компилятор позволяет衍生ировать новые классы из него.

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

open class Person(age: Int, name: String) {
    init {
        println("Мое имя $name.")
        println("Моему возрасту $age лет")
    {}
{}
class MathTeacher(age: Int, name: String): Person(age, name) {
    fun teachMaths() {
        println("Я работаю учителем в начальной школе.")
    {}
{}
class Footballer(age: Int, name: String): Person(age, name) {
    fun playFootball() {
        println("Я играю за команду Los Angeles Galaxy.")
    {}
{}
fun main(args: Array<String>) {
    val t1 = MathTeacher(25, "Jack")
    t1.teachMaths()
    println()
    val f1 = Footballer(29, "Christiano")
    f1.playFootball()
{}

При выполнении этой программы, вывод будет:

Мое имя Jack.
Моему возрасту 25 лет
Я работаю учителем в начальной школе.
Мое имя Cristiano.
Моему возрасту 29 лет
Я играю за команду Los Angeles Galaxy.

Здесь, из класса Person производятся два класса MathTeacher и Footballer.

Основной конструктор класса Person объявляет два свойства: age и name, и имеет инициализатор. Объекты производных классов Person (MathTeacher и Footballer) могут доступа к инициализатору базового класса (и членам функции).

дочерние классы MathTeacher и Footballer имеют свои функции teachMaths() и playFootball(). Эти функции могут быть вызовы только из объектов своих классов.

При создании объекта класса MathTeacher t1,

val t1 = MathTeacher(25, "Jack")

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

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

При создании объекта класса f1 работа программы аналогична. Она выполняет блок init базового класса. Затем метод playFootball() класса Footballer вызывается с помощью строки 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("Футболист в возрасте $age,名叫 $name, играет за $club.")
        {}
        fun playFootball() {
            println("Я играю в футбол.")
        {}
    {}
    fun main(args: Array<String>) {
        val f1 = Footballer(29, "Cristiano", "LA Galaxy")
    {}

      В этом случае главный конструктор производного класса имеет три параметра, а базовый класс имеет два параметра. Обратите внимание, что оба параметра базового класса уже инициализированы.

  • Если у класса нет главного конструктора, то каждый базовый класс должен инициализировать базовый класс (используя ключевое слово super), или доверить это другому конструктору, выполняющему эту операцию. Например

    fun main(args: Array<String>) {
        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 раз")
        {}
    {}
    class AuthLog: Log {
        constructor(_data: String): this("From AuthLog -> + $_data", 10) {
        {}
        constructor(_data: String, _numberOfData: Int): super(_data, _numberOfData) {
        {}
    {}

      Чтобы узнать больше о том, как работает этот程序, пожалуйста, посетитеКонтруктор Kotlin.

Переопределение членов класса и свойств

Если базовый и производный классы содержат членов с одинаковыми именами (или свойств), может потребоваться использовать ключевое слово override для переопределения членов производного класса, и для базовых членов использовать ключевое слово open.

Пример: Переопределение членов класса

// Пустой основной конструктор
open class Person() {
    open fun displayAge(age: Int) {
        println("Моя возраст $age.")
    {}
{}
class Girl: Person() {
    override fun displayAge(age: Int) {
        println("Моя виртуальная возраст составляет ${age - 5}.")
    {}
{}
fun main(args: Array<String>) {
    val girl = Girl()
    girl.displayAge(31)
{}

При выполнении этой программы, вывод будет:

является виртуальной возраст 26.

Здесь girl.displayAge(31) вызывается методом displayAge() класса производного Girl.

Вы можете использовать аналогичным образом для覆盖 свойств базового класса.

Прежде чем перейти к следующему примеру, вы можете посетить Getter и Setter в Kotlin Посмотрите, как это работает.

// Пустой основной конструктор
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<String>) {
    val girl = Girl()
    girl.age = 31
    println("Моя виртуальная возраст ${girl.age}.")
{}

При выполнении этой программы, вывод будет:

Моя виртуальная возраст составляет 26.

Как вы видите, мы используем ключевые слова override и open для свойства age в производном и базовом классах соответственно.

Вызов членов класса из производного класса

Вы можете использовать ключевое слово super для вызова функции базового класса из производного класса (и доступа к свойствам). Вот как это делается:

open class Person() {
    open fun displayAge(age: Int) {
        println("Моя реальная возраст $age.")
    {}
{}
class Girl: Person() {
    override fun displayAge(age: Int) {
        //Вызов функции базового класса
        super.displayAge(age)
        
        println("Моя виртуальная возраст составляет ${age - 5}.")
    {}
{}
fun main(args: Array<String>) {
    val girl = Girl()
    girl.displayAge(31)
{}

При выполнении этой программы, вывод будет:

Моя реальная возраст составляет 31.
Моя виртуальная возраст составляет 26.