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

Kotlin 继承

この記事では、継承について学びます。具体的には、継承とは何か、Kotlinでどのように実装するかについて説明します(例を用いて)。

継承はオブジェクト指向プログラミングの重要な機能の1つであり、ユーザーが既存のクラス(基クラス)から新しいクラス(派生クラス)を作成することができます。

派生クラスは基クラスのすべての機能を継承し、独自の機能も持つことができます。

Kotlinの継承について詳しく説明する前に、以下の2つの記事を読むことをお勧めします:

継承の理由は何ですか?

あなたのアプリケーションに3つのキャラクターが必要な場合-と数学教師(MathTeacher)とサッカー選手(Footballer)と商人(Businessman)

すべてのキャラクターが人であるため、彼らは歩くと話すことができます。しかし、彼らには特別なスキルもあります。数学教師は数学を教えます(teachMath)、そしてサッカー選手はサッカーを踢きます(playFootball)では、商人は企業を経営する(runBusiness)

それぞれ歩く、話す、そして特別なスキルを実行できる3つのクラスを別々に作成できます。

各クラスでは、各キャラクターに対して同じ歩行や話すコードをコピーします。

新しい機能を追加する場合 - eat(食べる)の場合、各キャラクターに対して同じコードを実装する必要があります。これはエラー(コピー中)やコードの重複につながりやすくて簡単に間違うことがあります。

もし基本的な機能を持つPersonクラスがあれば、例えば、歩く、食べる、寝る、そして役割に応じてこれらの機能に特別なスキルを追加すると、それはもっと簡単です。これは継承によって完了されます。

継承を使用することで、各クラスに同じwalk()、talk()、eat()コードを実装する必要がなくなります。あなたはただ継承それで十分です。

したがって、MathTeacher(派生クラス)では、Person(基クラス)のすべての機能を継承し、新しい機能 teachingMath()を追加できます。同様に、Footballerクラスでは、Personクラスのすべての機能を継承し、新しい機能 playFootball()を追加します。これらを続けていきます。

これにより、コードが簡潔で理解しやすく、拡張性があります。

重要なのは、継承の処理では、各派生クラスは「基」クラスであるかどうかの条件を満たすべきです。上の例では、MathTeacherはPerson(人)であり、FootballerはPerson(人)です。"商人(Businessman)は企業(Business)"と考えてはいけません。

Kotlinの継承

让我们尝试在代码中实现以上讨论:

open class Person(age: Int) {
    //食事、話し、歩くコード
}
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("私はロサンゼルス・ギャラクシーに所属しています。")
    }
}
fun main(args: Array<String>) {
    val t1 = MathTeacher(25, "Jack")
    t1.teachMaths()
    println()
    val f1 = Footballer(29, "Christiano")
    f1.playFootball()
}

このプログラムを実行すると、出力は以下の通りです:

私の名前は Jack。
私の年齢は 25
私は小学校で教えています。
私の名前は Cristiano。
私の年齢は 29
私はロサンゼルス・ギャラクシーに所属しています。

ここでは、Person クラスから二つのクラス、MathTeacher と Footballer が派生されています。

Person クラスの主要なコンストラクタは、age と name の二つの属性を宣言し、初期化ブロックを持っています。Person 派生クラス(MathTeacher と Footballer)のオブジェクトは、基底クラスの初期化ブロック(およびメンバーファンクション)にアクセスできます。

派生クラス MathTeacher と Footballer はそれぞれ独自のメンバーファンクション teachMaths() と playFootball() を持っています。これらのファンクションは、それぞれのクラスのオブジェクトからのみアクセスできます。

当创建 MathTeacher 类的对象 t 时1 时,

val t1 = MathTeacher(25, "Jack")

参数将传递给主构造函数。 在 Kotlin 中,创建对象时会调用 init 块。 由于 MathTeacher 是从 Person 类派生的,因此它将在基类(Person)中查找初始化程序块并执行它。 如果 MathTeacher 具有 init 块,则编译器还将执行派生类的 init 块。

接下来,使用 t1.teachMaths() 语句调用对象 t1的 teachMaths() 函数。

创建类的对象 f1 时,该程序的工作原理类似。 它执行基类的 init 块。 然后,使用语句 f1.playFootball() 调用 Footballer 类的 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")
    }

      在此,派生类的主要构造函数具有3个参数,而基类具有2个参数。请注意,基类的两个参数均已初始化。

  • 如果没有主构造函数,则每个基类都必须初始化基类(使用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) 派生クラス Girl の displayAge() メソッドを呼び出します。

基底クラスの属性を覆す方法も同様です。

以下の例を学ぶ前に、アクセスできます。 Kotlinの getter と setter 動作を確認してください。

//空のメインコンストラクタ
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.

ご覧の通り、age 属性に対して派生クラスと基底クラスでそれぞれ override と open キーワードを使用しています。

派生クラスから基底クラスメンバーの呼び出し

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.