Z tego artykułu dowiesz się o dziedziczeniu. Dokładniej, czym jest dziedziczenie i jak je zaimplementować w Kotlinie (na przykładach).
Dziedziczenie jest jedną z kluczowych cech programowania obiektowego. Pozwala użytkownikowi na utworzenie nowej klasy (klasy pochodnej) z istniejącej klasy (klasy bazowej).
Klasa pochodna dziedziczy wszystkie funkcje z klasy bazowej i może mieć własne dodatkowe funkcje.
Zanim przejdziemy do szczegółów dotyczących dziedziczenia Kotlin, zalecamy zapoznanie się z tymi dwoma artykułami:
- Klasa Kotlin i obiekty
- Główny konstruktor Kotlin
Dlaczego dziedziczenie?
Załóżmy, że w swojej aplikacji potrzebujesz trzech postaci - nauczyciela matematyki , piłkarza i biznesmena .
Ponieważ wszystkie postacie są osobami, mogą chodzić i mówić. Jednak mają też specjalne umiejętności. Nauczyciel matematyki może uczyć matematyki , piłkarz może grać w piłkę nożną, a biznesmen może prowadzić biznes .
Możesz indywidualnie stworzyć trzy klasy, które mogą chodzić, rozmawiać i wykonywać swoje specjalne umiejętności.
Na każdej z klas kopiowałbyś ten sam kod na spacer i rozmowę dla każdej postaci.
Jeśli chcesz dodać nową funkcję - jeść, musisz zaimplementować ten sam kod dla każdego znaku. Może to łatwo stać się podatne na błędy (podczas kopiowania) i zduplikować kody.
Byłoby o wiele łatwiej, gdybyśmy mieli Person
klasę z podstawowymi funkcjami, takimi jak rozmowa, chodzenie, jedzenie, spanie i dodawanie specjalnych umiejętności do tych funkcji, zgodnie z naszymi postaciami. Odbywa się to za pomocą dziedziczenia.
Korzystanie z dziedziczenia, teraz nie realizują ten sam kod walk()
, talk()
a eat()
dla każdej klasy. Musisz je tylko odziedziczyć .
Tak więc w przypadku MathTeacher
(klasa pochodna) dziedziczysz wszystkie funkcje Person
(klasy bazowej) i dodajesz nową funkcję teachMath()
. Podobnie w przypadku Footballer
klasy dziedziczysz wszystkie cechy Person
klasy, dodajesz nową funkcję playFootball()
i tak dalej.
Dzięki temu Twój kod jest czystszy, zrozumiały i rozszerzalny.
Ważne jest, aby pamiętać: podczas pracy z dziedziczeniem każda klasa pochodna powinna spełniać warunek, czy „jest” klasą bazową, czy nie. W powyższym przykładzie MathTeacher
to a Person
, Footballer
to a Person
. Nie możesz mieć czegoś takiego jak, Businessman
jest Business
.
Dziedziczenie Kotlin
Spróbujmy zaimplementować powyższą dyskusję w kodzie:
klasa otwarta Osoba (wiek: Int) (// kod do jedzenia, mówienia, chodzenia) klasa MathTeacher (wiek: Int): Osoba (wiek) (// inne cechy nauczyciela matematyki) klasa Piłkarz (wiek: Int): Osoba ( wiek) (// inne cechy piłkarza) klasa Przedsiębiorca (wiek: Int): Osoba (wiek) (// inne cechy biznesmena)
Tutaj Person
jest klasą bazową, a zajęcia MathTeacher
, Footballer
i Businessman
pochodzą z klasy Person.
Wskazówki, słowo open
zanim klasy bazowej Person
. To ważne.
Domyślnie zajęcia w Kotlinie są ostateczne. Jeśli znasz język Java, wiesz, że klasy końcowej nie można podklasy. Korzystając z otwartej adnotacji w klasie, kompilator umożliwia tworzenie z niej nowych klas.
Przykład: Dziedziczenie 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() )
Po uruchomieniu programu wynik będzie następujący:
Mam na imię Jack. Mam 25 lat i uczę w szkole podstawowej. Mam na imię Cristiano. Mam 29 lat, gram w LA Galaxy.
Tutaj dwie klasy MathTeacher
i Footballer
są pochodnymi Person
klasy.
Podstawowy konstruktor Person
klasy zadeklarował dwie właściwości: wiek i nazwę oraz ma blok inicjatora. Dostęp do bloku inicjującego (i funkcji składowych) klasy bazowej Person
można uzyskać za pomocą obiektów klas pochodnych ( MathTeacher
i Footballer
).
Klasy pochodne MathTeacher
i Footballer
mają własne funkcje członkowskie teachMaths()
i playFootball()
odpowiednio. Funkcje te są dostępne tylko z obiektów odpowiedniej klasy.
Kiedy MathTeacher
tworzony jest obiekt t1 klasy,
val t1 = MathTeacher (25, "Jack")
Parametry są przekazywane do głównego konstruktora. W Kotlinie init
blok jest wywoływany podczas tworzenia obiektu. Ponieważ MathTeacher
jest pochodną Person
klasy, szuka bloku inicjatora w klasie bazowej (Person) i wykonuje go. Gdyby MathTeacher
miał blok init, kompilator wykonałby również blok init klasy pochodnej.
Następnie wywoływana jest teachMaths()
funkcja obiektu t1
using t1.teachMaths()
instrukcji.
Program działa podobnie, gdy obiekt f1
z Footballer
klasy jest tworzony. Wykonuje blok init klasy bazowej. Następnie wywoływana jest playFootball()
metoda Footballer
klasy using instrukcja f1.playFootball()
.
Ważne uwagi: Dziedziczenie Kotlin
- Jeśli klasa ma konstruktora podstawowego, podstawę należy zainicjować przy użyciu parametrów konstruktora podstawowego. W powyższym programie obie klasy pochodne mają dwa parametry
age
iname
, a oba te parametry są inicjowane w konstruktorze podstawowym w klasie bazowej.
Oto kolejny przykład: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") )
- W przypadku braku konstruktora podstawowego każda klasa bazowa musi zainicjować bazę (za pomocą słowa kluczowego super) lub przekazać ją innemu konstruktorowi, który to robi. Na przykład,
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) ( ) )
Zastępowanie funkcji i właściwości składowych
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
Możesz wywołać funkcje (i uzyskać dostęp do właściwości) klasy bazowej z klasy pochodnej za pomocą super
słowa kluczowego. Oto jak:
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) )
Po uruchomieniu programu wynik będzie następujący:
Mam 31 lat. Mój fałszywy wiek to 26 lat.