In diesem Artikel erfahren Sie mehr über Vererbung. Genauer gesagt, was ist Vererbung und wie wird sie in Kotlin implementiert (anhand von Beispielen)?
Vererbung ist eines der Hauptmerkmale der objektorientierten Programmierung. Es ermöglicht dem Benutzer, eine neue Klasse (abgeleitete Klasse) aus einer vorhandenen Klasse (Basisklasse) zu erstellen.
Die abgeleitete Klasse erbt alle Features von der Basisklasse und kann zusätzliche eigene Features haben.
Bevor Sie auf Details zur Kotlin-Vererbung eingehen, empfehlen wir Ihnen, diese beiden Artikel zu lesen:
- Kotlin Klasse und Objekte
- Kotlin Primärkonstruktor
Warum Vererbung?
Angenommen, Sie möchten in Ihrer Bewerbung drei Charaktere - einen Mathematiklehrer , einen Fußballspieler und einen Geschäftsmann .
Da alle Charaktere Personen sind, können sie gehen und sprechen. Sie haben jedoch auch einige besondere Fähigkeiten. Ein Mathematiklehrer kann Mathematik unterrichten , ein Fußballspieler kann Fußball spielen und ein Geschäftsmann kann ein Geschäft führen .
Sie können individuell drei Klassen erstellen, die gehen, sprechen und ihre besonderen Fähigkeiten ausführen können.
In jeder der Klassen würden Sie für jedes Zeichen denselben Code für Gehen und Sprechen kopieren.
Wenn Sie eine neue Funktion hinzufügen möchten, müssen Sie für jedes Zeichen denselben Code implementieren. Dies kann leicht fehleranfällig werden (beim Kopieren) und doppelte Codes.
Es wäre viel einfacher, wenn wir eine Person
Klasse mit grundlegenden Funktionen wie Sprechen, Gehen, Essen, Schlafen hätten und diesen Funktionen gemäß unseren Charakteren besondere Fähigkeiten hinzufügen würden. Dies erfolgt durch Vererbung.
Vererbung, jetzt implementieren Sie nicht den gleichen Code für walk()
, talk()
und eat()
für jede Klasse. Sie müssen sie nur erben .
Für MathTeacher
(abgeleitete Klasse) erben Sie also alle Features einer Person
(Basisklasse) und fügen ein neues Feature hinzu teachMath()
. Ebenso Footballer
erben Sie für die Klasse alle Funktionen der Person
Klasse und fügen eine neue Funktion hinzu playFootball()
und so weiter.
Dies macht Ihren Code sauberer, verständlicher und erweiterbarer.
Es ist wichtig, sich daran zu erinnern: Wenn Sie mit Vererbung arbeiten, sollte jede abgeleitete Klasse die Bedingung erfüllen, ob es sich um eine Basisklasse handelt oder nicht. Im obigen Beispiel MathTeacher
ist a Person
, Footballer
ist a Person
. Sie können so etwas nicht haben, Businessman
ist ein Business
.
Kotlin-Vererbung
Versuchen wir, die obige Diskussion im Code zu implementieren:
offene Klasse Person (Alter: Int) (// Code zum Essen, Sprechen, Gehen) Klasse MathTeacher (Alter: Int): Person (Alter) (// andere Merkmale des Mathematiklehrers) Klasse Footballer (Alter: Int): Person ( Alter) (// andere Merkmale des Fußballspielers) Klasse Geschäftsmann (Alter: Int): Person (Alter) (// andere Merkmale des Geschäftsmanns)
Hier Person
ist eine Basisklasse und Klassen MathTeacher
, Footballer
und Businessman
sind von der Person - Klasse abgeleitet.
Beachten Sie, das Schlüsselwort open
vor der Basisklasse Person
. Es ist wichtig.
Standardmäßig sind Klassen in Kotlin endgültig. Wenn Sie mit Java vertraut sind, wissen Sie, dass eine endgültige Klasse nicht in Unterklassen unterteilt werden kann. Durch die Verwendung der offenen Annotation für eine Klasse können Sie mit dem Compiler neue Klassen daraus ableiten.
Beispiel: Kotlin-Vererbung
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() )
Wenn Sie das Programm ausführen, lautet die Ausgabe wie folgt:
Ich heiße Jack. Ich bin 25 Jahre alt und unterrichte in der Grundschule. Ich heiße Cristiano. Ich bin 29 Jahre alt und spiele für LA Galaxy.
Hier zwei Klassen MathTeacher
und Footballer
werden von der Person
Klasse abgeleitet.
Der primäre Konstruktor der Person
Klasse deklarierte zwei Eigenschaften: Alter und Name und verfügt über einen Initialisierungsblock. Auf den Initilizer-Block (und die Elementfunktionen) der Basisklasse Person
können die Objekte abgeleiteter Klassen ( MathTeacher
und Footballer
) zugreifen .
Abgeleitete Klassen MathTeacher
und Footballer
haben ihre eigenen Mitgliedsfunktionen teachMaths()
und playFootball()
jeweils. Auf diese Funktionen kann nur von den Objekten der jeweiligen Klasse aus zugegriffen werden.
Wenn das Objekt t1 der MathTeacher
Klasse erstellt wird,
val t1 = MathTeacher (25, "Jack")
Die Parameter werden an den primären Konstruktor übergeben. In Kotlin wird der init
Block beim Erstellen des Objekts aufgerufen. Da MathTeacher
es von der Person
Klasse abgeleitet ist , sucht es in der Basisklasse (Person) nach dem Initialisierungsblock und führt ihn aus. Wenn der MathTeacher
Init-Block hätte, hätte der Compiler auch den Init-Block der abgeleiteten Klasse ausgeführt.
Als nächstes wird die teachMaths()
Funktion für das Objekt t1
mit der t1.teachMaths()
Anweisung aufgerufen .
Das Programm funktioniert auf ähnliche Weise , wenn das Objekt f1
der Footballer
Klasse erstellt wird. Es führt den Init-Block der Basisklasse aus. Dann wird die playFootball()
Methode der Footballer
Klasse using-Anweisung aufgerufen f1.playFootball()
.
Wichtige Hinweise: Kotlin-Vererbung
- Wenn die Klasse einen Primärkonstruktor hat, muss die Basis mit den Parametern des Primärkonstruktors initialisiert werden. Im obigen Programm haben beide abgeleiteten Klassen zwei Parameter
age
undname
, und beide Parameter werden im Primärkonstruktor in der Basisklasse initialisiert.
Hier ist ein weiteres Beispiel: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") )
- Wenn kein primärer Konstruktor vorhanden ist, muss jede Basisklasse die Basis initialisieren (mit dem Schlüsselwort super) oder an einen anderen Konstruktor delegieren, der dies tut. Beispielsweise,
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) ( ) )
Überschreiben von Elementfunktionen und -eigenschaften
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
Sie können Funktionen (und Zugriffseigenschaften) der Basisklasse von einer abgeleiteten Klasse mit dem super
Schlüsselwort aufrufen . Hier ist wie:
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) )
Wenn Sie das Programm ausführen, lautet die Ausgabe wie folgt:
Mein Alter ist 31. Mein falsches Alter ist 26.