In questo articolo imparerai l'ereditarietà. Più specificamente, cos'è l'ereditarietà e come implementarla in Kotlin (con l'aiuto di esempi).
L'ereditarietà è una delle caratteristiche chiave della programmazione orientata agli oggetti. Consente all'utente di creare una nuova classe (classe derivata) da una classe esistente (classe base).
La classe derivata eredita tutte le funzionalità dalla classe base e può avere funzionalità aggiuntive proprie.
Prima di entrare nei dettagli sull'eredità di Kotlin, ti consigliamo di controllare questi due articoli:
- Classe e oggetti di Kotlin
- Costruttore primario di Kotlin
Perché l'eredità?
Supponi, nella tua applicazione, di volere tre personaggi: un insegnante di matematica , un calciatore e un uomo d'affari .
Poiché tutti i personaggi sono persone, possono camminare e parlare. Tuttavia, hanno anche alcune abilità speciali. Un insegnante di matematica può insegnare matematica , un calciatore può giocare a calcio e un uomo d'affari può gestire un'impresa .
Puoi creare individualmente tre classi che possono camminare, parlare ed eseguire le loro abilità speciali.
In ciascuna delle classi, copieresti lo stesso codice per camminare e parlare per ogni personaggio.
Se vuoi aggiungere una nuova funzionalità: mangia, devi implementare lo stesso codice per ogni personaggio. Questo può facilmente diventare soggetto a errori (durante la copia) e duplicare i codici.
Sarebbe molto più semplice se avessimo una Person
classe con caratteristiche di base come parlare, camminare, mangiare, dormire e aggiungere abilità speciali a quelle caratteristiche come per i nostri personaggi. Questo viene fatto usando l'ereditarietà.
Utilizzando l'ereditarietà, ora non si implementa lo stesso codice per walk()
, talk()
e eat()
per ogni classe. Hai solo bisogno di ereditarli .
Quindi, per MathTeacher
(classe derivata), erediti tutte le funzionalità di una Person
(classe base) e aggiungi una nuova funzionalità teachMath()
. Allo stesso modo, per la Footballer
classe, erediti tutte le caratteristiche della Person
classe e aggiungi una nuova caratteristica playFootball()
e così via.
Questo rende il tuo codice più pulito, comprensibile ed estendibile.
È importante ricordare: quando si lavora con l'ereditarietà, ogni classe derivata deve soddisfare la condizione se "è" una classe base o meno. Nell'esempio sopra, MathTeacher
è a Person
, Footballer
è a Person
. Non puoi avere qualcosa come, Businessman
è un Business
.
Eredità di Kotlin
Proviamo a implementare la discussione sopra nel codice:
classe aperta Persona (età: Int) (// codice per mangiare, parlare, camminare) classe MathTeacher (età: Int): Persona (età) (// altre caratteristiche dell'insegnante di matematica) classe Calciatore (età: Int): Persona ( età) (// altre caratteristiche del calciatore) classe Uomo d'affari (età: Int): Persona (età) (// altre caratteristiche dell'uomo d'affari)
Qui, Person
è una classe base, e le classi MathTeacher
, Footballer
e Businessman
sono derivate dalla classe Person.
Avviso, la parola chiave open
prima della classe base, Person
. È importante.
Per impostazione predefinita, le lezioni in Kotlin sono definitive. Se hai familiarità con Java, sai che una classe finale non può essere sottoclasse. Utilizzando l'annotazione aperta su una classe, il compilatore consente di derivarne nuove classi.
Esempio: ereditarietà di 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() )
Quando esegui il programma, l'output sarà:
Mi chiamo Jack. Ho 25 anni, insegno alle elementari. Il mio nome è Cristiano. La mia età è 29, gioco per LA Galaxy.
Qui, due classi MathTeacher
e Footballer
sono derivati dalla Person
classe.
Il costruttore principale della Person
classe ha dichiarato due proprietà: età e nome e ha un blocco di inizializzazione. È possibile accedere al blocco di inizializzazione (e alle funzioni membro) della classe di base Person
dagli oggetti delle classi derivate ( MathTeacher
e Footballer
).
Classi derivate MathTeacher
e Footballer
hanno le proprie funzioni membro teachMaths()
e playFootball()
rispettivamente. Queste funzioni sono accessibili solo dagli oggetti della rispettiva classe.
Quando MathTeacher
viene creato l'oggetto t1 della classe,
val t1 = MathTeacher (25, "Jack")
I parametri vengono passati al costruttore principale. In Kotlin, il init
blocco viene chiamato quando viene creato l'oggetto. Poiché, MathTeacher
è derivato dalla Person
classe, cerca il blocco inizializzatore nella classe base (Persona) e lo esegue. Se MathTeacher
avesse il blocco init, il compilatore avrebbe eseguito anche il blocco init della classe derivata.
Successivamente, la teachMaths()
funzione per oggetto t1
viene chiamata utilizzando l' t1.teachMaths()
istruzione.
Il programma funziona in modo simile quando viene creato l' oggetto f1
della Footballer
classe. Esegue il blocco di inizializzazione della classe base. Quindi, il playFootball()
metodo della Footballer
classe viene chiamato using statement f1.playFootball()
.
Note importanti: ereditarietà di Kotlin
- Se la classe ha un costruttore primario, la base deve essere inizializzata utilizzando i parametri del costruttore primario. Nel programma precedente, entrambe le classi derivate hanno due parametri
age
ename
, ed entrambi questi parametri sono inizializzati nel costruttore primario nella classe base.
Ecco un altro esempio: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") )
- In caso di nessun costruttore principale, ogni classe base deve inizializzare la base (usando la parola chiave super) o delegare a un altro costruttore che lo fa. Per esempio,
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) ( ) )
Sostituzione delle funzioni e delle proprietà dei membri
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
È possibile chiamare le funzioni (e accedere alle proprietà) della classe base da una classe derivata utilizzando la super
parola chiave. Ecco come:
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) )
Quando esegui il programma, l'output sarà:
La mia età è 31. La mia età falsa è 26.