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

Kotlin 继承

In questo articolo, imparerai l'ereditarietà. In particolare, cosa è l'ereditarietà e come si realizza l'ereditarietà in Kotlin (attraverso esempi).

L'ereditarietà è una delle funzionalità chiave dell'orientamento agli oggetti. Permette agli utenti di creare una nuova classe (classe derivata) da una classe esistente (classe base).

Le classi derivate ereditano tutte le funzionalità della classe base e possono avere altre funzionalità proprie.

Prima di approfondire l'ereditarietà in Kotlin, ti consiglio di leggere gli articoli seguenti:

Perché ereditare?

Supponiamo che nel tuo applicativo siano necessari tre ruoli - uninsegnante di matematica(MathTeacher), uncalciatore(Footballer) e unimprenditore (Businessman).

Poiché tutti i ruoli sono persone, possono camminare e parlare. Ma hanno anche alcune abilità speciali. Il insegnante di matematica puòinsegnare matematica (teachMath)e il calciatore puòcalcio(playFootball), l'imprenditore puòGestire l'impresa (runBusiness).

Puoi creare tre classi separate che possono camminare, parlare e eseguire le loro abilità speciali.

In ogni classe, copierai lo stesso codice di camminare e parlare per ogni ruolo.

Se si desidera aggiungere una nuova caratteristica - mangiare (mangiare), allora è necessario implementare lo stesso codice per ogni ruolo. Questo può facilmente portare a errori (durante la copia) e codice ripetuto.

Se abbiamo una classe Person con funzionalità di base, ad esempio, camminare, mangiare, dormire e aggiungere abilità speciali per i nostri ruoli, sarà molto più facile. Questo è fatto tramite l'ereditarietà.

Usando l'ereditarietà, non devi implementare lo stesso codice walk(), talk() e eat() per ogni classe. Devi soloEreditarietàBasta così.

Quindi, per MathTeacher (classe derivata), puoi ereditare tutte le funzionalità di Person (classe base) e aggiungere una nuova funzione teachingMath(). Allo stesso modo, per la classe Footballer, erediti tutte le funzionalità della classe Person e aggiungi una nuova funzione playFootball(), e così via.

Questo rende il tuo codice più semplice, comprensibile ed estensibile.

È importante ricordare che:Quando si gestisce l'ereditarietà, ogni classe derivata dovrebbe soddisfare i requisiti di essere una 'classe base'. Nel nostro esempio, MathTeacher è una Person (persona), Footballer è una Person (persona). Non si può pensare che 'imprenditore (Businessman) sia impresa (Business)'.

Ereditarietà Kotlin

Proviamo a implementare nel codice ciò che è stato discusso:

open class Person(age: Int) {
    //Mangiare, parlare, camminare codice
}
class MathTeacher(age: Int): Person(age) {
    // Altre caratteristiche dell'insegnante di matematica
}
class Footballer(age: Int): Person(age) {
    // Altre caratteristiche del calciatore
}
class Businessman(age: Int): Person(age) {
    // Altre caratteristiche del commerciante
}

Qui, Person è la classe base, mentre le classi MathTeacher, Footballer e Businessman sono derivate dalla classe Person.

Attenzione, la parola chiave open prima della classe base Person è molto importante.

Per default, le classi in Kotlin sono finali. Se sei familiare con Java, saprai che le classi final non possono essere derivate. Utilizzando l'annotazione, il compilatore permette di derivare nuove classi da essa.

Esempio: ereditarietà Kotlin

aperta classe Person(age: Int, name: String) {
    init {
        println("Il mio nome è $name.")
        println("La mia età è $age")
    }
}
class MathTeacher(age: Int, name: String): Person(age, name) {
    fun teachMaths() {
        println("Insegnò alla scuola elementare.")
    }
}
class Footballer(age: Int, name: String): Person(age, name) {
    fun playFootball() {
        println("Gioco per la Los Angeles Galaxy.")
    }
}
fun main(args: Array<String>) {
    val t1 = MathTeacher(25, "Jack")
    t1.teachMaths()
    println()
    val f1 = Footballer(29, "Christiano")
    f1.playFootball()
}

运行该程序时,输出为:

Il mio nome è Jack.
La mia età è 25
Insegnò alla scuola elementare.
Il mio nome è Cristiano.
La mia età è 29
Gioco per la Los Angeles Galaxy.

Qui, sono state derivate due classi MathTeacher e Footballer dalla classe Person.

Il costruttore principale della classe Person dichiara due attributi: age e name, e ha un blocco di inizializzazione. Gli oggetti delle classi derivate da Person (MathTeacher e Footballer) possono accedere al blocco di inizializzazione (e ai membri funzionali) della classe base.

le classi derivate MathTeacher e Footballer hanno rispettivamente i loro membri funzionali teachMaths() e playFootball(). Queste funzioni possono essere accedute solo dagli oggetti delle rispettive classi.

Quando si crea l'oggetto della classe MathTeacher t1,

val t1 = MathTeacher(25, "Jack")

I parametri vengono passati al costruttore principale. In Kotlin, quando si crea un oggetto viene chiamato il blocco init. Poiché MathTeacher è derivato dalla classe Person, esegue il blocco init della superclasse (Person). Se MathTeacher ha un blocco init, il compilatore esegue anche il blocco init della classe deriva.

Successivamente, chiama la funzione teachMaths() dell'oggetto t1 utilizzando la frase t1.teachMaths().

Quando si crea un oggetto della classe f1, il funzionamento del programma è simile. Esegue il blocco init della superclasse. Poi, chiama il metodo playFootball() della classe Footballer utilizzando la frase f1.playFootball().

Notazione importante: ereditarietà in Kotlin

  • Se la classe ha un costruttore principale, deve utilizzare i parametri del costruttore principale per inizializzare la superclasse. Nel programma sopra, entrambe le classi derivate hanno due parametri age e name, e questi parametri sono stati inizializzati nel costruttore principale della superclasse.
    Ecco un altro esempio:

    aperta classe Person(age: Int, name: String) {
        // some code
    }
    classe Footballer(age: Int, name: String, club: String): Person(age, name) {
        init {
            stampa("Il calciatore di età $age, $name, gioca per $club.")
        }
        fun playFootball() {
            stampa("Sto calcendo a football.")
        }
    }
    fun main(args: Array<String>) {
        val f1 = Footballer(29, "Cristiano", "LA Galaxy")
    }

      In questo caso, il costruttore principale della classe deriva ha 3 parametri, mentre la superclasse ha 2 parametri. Notare che entrambi i parametri della superclasse sono stati inizializzati.

  • Se non c'è un costruttore principale, ogni superclasse deve inizializzare la superclasse (usando il nome chiave super), o delegare a un altro costruttore che esegue questa operazione. Ad esempio

    fun main(args: Array<String>) {
        val p1 = AuthLog("Password errato")
    }
    aperta classe Log {
        var data: String = ""
        var numberOfData = 0
        costruttore(_data: String) {
        }
        costruttore(_data: String, _numberOfData: Int) {
            data = _data
            numberOfData = _numberOfData
            println("$data: $numberOfData volte")
        }
    }
    class AuthLog: Log {
        constructor(_data: String): this("From AuthLog -> + $_data", 10) {
        }
        constructor(_data: String, _numberOfData: Int): super(_data, _numberOfData) {
        }
    }

      Per ulteriori informazioni su come funziona questo programma, visitaCostruttore secondario Kotlin.

Sovrascrittura dei membri e delle proprietà

Se la classe base e la classe derivata contengono membri con lo stesso nome (o proprietà), potrebbe essere necessario sovrascrivere i membri della classe derivata utilizzando la parola chiave override e utilizzare la parola chiave open per i membri della classe base.

Esempio: sovrascrittura dei membri

// Costruttore principale vuoto
open class Person() {
    open fun displayAge(age: Int) {
        println("La mia età è $age.")
    }
}
class Girl: Person() {
    override fun displayAge(age: Int) {
        println("我的虚拟年龄是 ${age - 5}.")
    }
}
fun main(args: Array<String>) {
    val girl = Girl()
    girl.displayAge(31)
}

运行该程序时,输出为:

La mia età virtuale è 26.

In questo caso, girl.displayAge(31) chiama il metodo displayAge() della classe derivata Girl.

Puoi sovrascrivere le proprietà della classe base in modo simile.

Prima di studiare gli esempi seguenti, puoi accedere a Kotlin的 getter 和 setter Vedere come funziona.

// Costruttore principale vuoto
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("La mia età virtuale è ${girl.age}.")
}

运行该程序时,输出为:

我的虚拟年龄是 26.

Come puoi vedere, abbiamo utilizzato le parole chiave override e open per l'attributo age sia nella classe derivata che nella classe base.

Chiamare i membri della classe base dalla classe derivata

Puoi utilizzare la parola chiave super per chiamare le funzioni della classe base dalla classe derivata (e accedere alle proprietà). Ecco come fare:

open class Person() {
    open fun displayAge(age: Int) {
        println("La mia età reale è $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.