Kotlin ist eine moderne Programmiersprache, die Java-Bytecode kompiliert. Es ist kostenlos und Open Source und verspricht, die Kodierung für Android noch mehr Spaß zu machen.
Im vorigen Artikel haben Sie mehr über Kotlin-Eigenschaften wie späte Initialisierung, Erweiterung und Inline-Eigenschaften erfahren. Außerdem haben Sie in Kotlin fortgeschrittene Klassen wie Daten, Aufzählungen, verschachtelte und versiegelte Klassen kennen gelernt.
In diesem Beitrag erfahren Sie weiter über objektorientierte Programmierung in Kotlin, indem Sie abstrakte Klassen, Schnittstellen und Vererbung lernen. Für einen Bonus erfahren Sie auch mehr über Typ-Aliase.
Kotlin unterstützt abstrakte Klassen - genau wie Java sind dies Klassen, aus denen Sie niemals Objekte erstellen möchten. Eine abstrakte Klasse ist unvollständig oder unbrauchbar ohne einige konkrete (nicht abstrakte) Unterklassen, aus denen Sie Objekte instanziieren können. Eine konkrete Unterklasse einer abstrakten Klasse implementiert alle in der abstrakten Klasse definierten Methoden und Eigenschaften. Andernfalls ist diese Unterklasse auch eine abstrakte Klasse!
Wir erstellen eine abstrakte Klasse mit der abstrakt
Modifikator (ähnlich wie Java).
abstrakte Klasse Angestellter (val firstName: String, val lastName: String) abstraktes Einkommen (): doppelt
Beachten Sie, dass nicht alle Mitglieder abstrakt sein müssen. Mit anderen Worten, wir können eine Methodenstandardimplementierung in einer abstrakten Klasse haben.
abstrakte Klasse Employee (Wert Vorname: Zeichenfolge, Wert Nachname: Zeichenfolge) //… fun fullName (): Zeichenfolge Rückgabe Nachname + "" + Vorname;
Hier haben wir die nicht abstrakte Funktion erstellt vollständiger Name()
in einer abstrakten Klasse Mitarbeiter
. Konkrete Klassen (Unterklassen der abstrakten Klasse) können die Standardimplementierung einer abstrakten Methode überschreiben. Dies ist jedoch nur möglich, wenn die Methode die öffnen
Modifier angegeben (Sie werden in Kürze mehr darüber erfahren).
Wir können Zustände auch in abstrakten Klassen speichern.
abstrakte Klasse Angestellter (val firstName: String, val lastName: String) //… val propFoo: String = "bla bla"
Selbst wenn die abstrakte Klasse keine Methoden definiert, müssen Sie eine Unterklasse erstellen, bevor Sie sie instanziieren können (siehe Beispiel unten).
Klasse Programmierer (firstName: String, lastName: String): Angestellter (firstName, lastName) Überschreibe Spaßverdienst (): Verdoppeln // Verdienst berechnen
Unsere Programmierer
Klasse erweitert die Mitarbeiter
abstrakte Klasse. In Kotlin verwenden wir einen einzelnen Doppelpunkt (:
) anstelle von Java erweitert
Schlüsselwort, um eine Klasse zu erweitern oder eine Schnittstelle zu implementieren.
Wir können dann ein Objekt vom Typ erstellen Programmierer
und ruft Methoden auf - entweder in seiner eigenen Klasse oder in der Superklasse (Basisklasse).
val programmer = Programmierer ("Chike", "Mgbemena") println (Programmierer.fullName ()) // "Mgbemena Chike"
Eine Sache, die Sie überraschen könnte, ist, dass wir die Möglichkeit haben, ein zu überschreiben val
(unveränderliches) Eigentum mit var
(veränderlich).
Offene Klasse BaseA (Open Val BaseProp: String) Klasse DerivedA: BaseA ("") private var AbgeleiteteProp: String = "" Überschreiben Sie Var BaseProp: String get () = AbgeleitetePropmenge (Wert) AbgeleiteteProp = Wert
Stellen Sie sicher, dass Sie diese Funktionalität sinnvoll einsetzen! Beachten Sie, dass wir die umgekehrte Überschreibung nicht ausführen können var
Eigentum mit val
.
Eine Schnittstelle ist einfach eine Sammlung verwandter Methoden, mit denen Sie Objekten normalerweise mitteilen können, was zu tun ist und wie es standardmäßig zu tun ist. (Standardmethoden in Schnittstellen sind eine neue Funktion, die Java 8 hinzugefügt wurde.) Mit anderen Worten, eine Schnittstelle ist ein Vertrag, an den sich die Implementierung von Klassen halten muss.
Eine Schnittstelle wird mit definiert Schnittstelle
Stichwort in Kotlin (ähnlich wie Java).
Klasse Ergebnisklasse Schüleroberfläche StudentRepository fun getById (id: Long): Student fun getResultsById (id: Long): Liste
Im obigen Code haben wir a erklärt StudentRepository
Schnittstelle. Diese Schnittstelle enthält zwei abstrakte Methoden: getById ()
und getResultsById ()
. Beachten Sie, dass die abstrakt
Schlüsselwort ist in einer Schnittstellenmethode redundant, da sie bereits implizit abstrakt sind.
Eine Schnittstelle ist ohne einen oder mehrere Implementierer unbrauchbar. Erstellen Sie also eine Klasse, die diese Schnittstelle implementiert.
Klasse StudentLocalDataSource: StudentRepository überschreibt fun getResults (id: Long): List// Implementierung ausführen überschreiben Spaß getById (id: Long): Student // Implementierung ausführen
Hier haben wir eine Klasse erstellt StudentLocalDataSource
das implementiert die StudentRepository
Schnittstelle.
Wir nehmen das überschreiben
Modifikator zum Beschriften der Methoden und Eigenschaften, die von der Schnittstelle oder der Superklasse aus neu definiert werden sollen. Dies ist ähnlich wie die @Überfahren
Annotation in Java.
Beachten Sie die folgenden zusätzlichen Regeln für Schnittstellen in Kotlin:
überschreiben
Modifier ist im Gegensatz zu Java in Kotlin obligatorisch. Sehen wir uns ein Beispiel für eine Schnittstellenmethode mit einer Standardimplementierung an.
Schnittstelle StudentRepository //… Spaß löschen (Student: Student) // Implementierung durchführen
Im vorhergehenden Code haben wir eine neue Methode hinzugefügt löschen()
mit einer Standardimplementierung (obwohl ich den tatsächlichen Implementierungscode nicht zu Demonstrationszwecken hinzugefügt habe).
Wir haben auch die Freiheit, die Standardimplementierung zu überschreiben, wenn wir möchten.
Klasse StudentLocalDataSource: StudentRepository //… überschreibe fun delete (student: Student) // Implementierung durchführen
Wie bereits erwähnt, kann eine Kotlin-Schnittstelle Eigenschaften haben. Beachten Sie jedoch, dass sie den Status nicht beibehalten kann. (Denken Sie jedoch daran, dass abstrakte Klassen den Status beibehalten können.) Daher funktioniert die folgende Schnittstellendefinition mit einer Eigenschaftendeklaration.
Schnittstelle StudentRepository val propFoo: Boolean // wird funktionieren //…
Wenn wir jedoch versuchen, der Schnittstelle einen Status hinzuzufügen, indem Sie der Eigenschaft einen Wert zuweisen, funktioniert dies nicht.
interface StudentRepository val propFoo: Boolean = true // Fehler: Eigenschaftsinitialisierer sind in Schnittstellen nicht zulässig. //…
Eine Interface-Eigenschaft in Kotlin kann jedoch Getter- und Setter-Methoden enthalten (allerdings nur die letztere, wenn die Eigenschaft veränderbar ist). Beachten Sie auch, dass die Eigenschaft in einer Schnittstelle kein Hintergrundfeld haben kann.
Schnittstelle StudentRepository var propFoo: Boolean get () = true set (value) if (value) // etwas tun //…
Wir können auch eine Schnittstelleneigenschaft überschreiben, wenn Sie möchten, um sie neu zu definieren.
Klasse StudentLocalDataSource: StudentRepository //… überschreiben var propFoo: Boolean get () = false set (value) if (value)
Betrachten wir einen Fall, in dem eine Klasse mehrere Schnittstellen mit derselben Methodensignatur implementiert. Wie entscheidet die Klasse, welche Schnittstellenmethode aufgerufen werden soll??
Schnittstelle InterfaceA fun funD () Schnittstelle InterfaceB fun funD ()
Hier haben wir zwei Schnittstellen, die eine Methode mit derselben Signatur haben Fonds()
. Erstellen wir eine Klasse, die diese beiden Schnittstellen implementiert und die. Überschreibt Fonds()
Methode.
class classA: InterfaceA, InterfaceB funD überschreiben funD () super.funD () // Fehler: Viele Supertypen sind verfügbar. Bitte geben Sie den Typ an, den Sie in spitzen Klammern meinen, z. 'Super'
Der Compiler ist verwirrt über den Aufruf von super.funD ()
Methode, weil die beiden Schnittstellen, die die Klasse implementiert, dieselbe Methodensignatur haben.
Um dieses Problem zu lösen, schließen wir den Namen der Schnittstelle ein, für die die Methode in spitzen Klammern aufgerufen werden soll
. (IntelliJ IDEA oder Android Studio gibt Ihnen einen Hinweis zur Lösung dieses Problems, wenn es auftritt.)
class classA: InterfaceA, InterfaceB überschreiben fun fun () super.funD ()
Hier nennen wir die Fonds()
Methode von InterfaceA
. Problem gelöst!
Eine neue Klasse (Unterklasse) wird erstellt, indem die Mitglieder einer übergeordneten Klasse (Oberklasse) einer vorhandenen Klasse erworben werden und möglicherweise ihre Standardimplementierung neu definiert wird. Dieser Mechanismus ist bekannt als Erbe in der objektorientierten Programmierung (OOP). Eines der Dinge, die Kotlin so fantastisch machen, ist, dass es sowohl die OOP- als auch die Funktionsprogrammierungsparadigmen umfasst - alles in einer Sprache.
Die Basisklasse für alle Klassen in Kotlin ist Irgendein
.
Klasse Person: beliebig
Das Irgendein
Typ entspricht dem Objekt
Typ, den wir in Java haben.
public open class Beliebig public open operator fun gleich (other: any?): Boolescher öffentlicher open-Spaß hashCode (): Int öffentlicher offener Spaß toString (): String
Das Irgendein
Typ enthält die folgenden Mitglieder: gleich ()
, Hash-Code()
, und auch toString ()
Methoden (ähnlich wie Java).
Unsere Klassen müssen diesen Typ nicht explizit erweitern. Wenn Sie nicht explizit angeben, welche Klasse eine neue Klasse erweitert, wird die Klasse erweitert Irgendein
implizit. Aus diesem Grund müssen Sie normalerweise nicht hinzufügen : Irgendein
in Ihrem Code - wir machen dies in dem obigen Code zu Demonstrationszwecken.
Lassen Sie uns nun einen Blick auf die Erstellung von Klassen in Kotlin mit Blick auf die Vererbung werfen.
Klasse Student Klasse GraduateStudent: Student ()
Im obigen Code steht der GraduateStudent
Klasse erweitert die Oberklasse Student
. Dieser Code wird jedoch nicht kompiliert. Warum? Weil Klassen und Methoden sind Finale
standardmäßig in Kotlin. Mit anderen Worten, sie können nicht standardmäßig erweitert werden - im Gegensatz zu Java, wo Klassen und Methoden standardmäßig geöffnet sind.
Best Practices für das Software-Engineering empfehlen Ihnen, mit dem Erstellen Ihrer Klassen und Methoden zu beginnen Finale
standardmäßig - d.h. wenn sie nicht ausdrücklich dazu bestimmt sind, in Unterklassen neu definiert oder überschrieben zu werden. Das Kotlin-Team (JetBrains) wendete diese Kodierungsphilosophie und viele weitere Best Practices für die Entwicklung dieser modernen Sprache an.
Um zu ermöglichen, dass Unterklassen aus einer Oberklasse erstellt werden, müssen wir die Oberklasse explizit mit der öffnen
Modifikator. Dieser Modifikator gilt auch für alle Superklasseigenschaften oder -methoden, die von Unterklassen überschrieben werden sollen.
Offene Klasse Student
Wir setzen einfach die öffnen
Modifikator vor dem Klasse
Stichwort. Wir haben jetzt den Compiler angewiesen, unsere zuzulassen Student
Klasse für Erweiterungen offen.
Wie bereits erwähnt, sind Mitglieder einer Kotlin-Klasse standardmäßig auch final.
open class Student open fun schoolFees (): BigDecimal // Implementierung ausführen
Im vorhergehenden Code haben wir das markiert Schulgebühren
funktionieren als öffnen
-so dass Unterklassen es überschreiben können.
Offene Klasse GraduateStudent: Student () Spaß überschreiben schoolFees (): BigDecimal return super.schoolFees () + berechneSchoolFees () privater Spaß berechneSchoolFees (): BigDecimal // Schulgebühren berechnen und zurückgeben
Hier das Offene Schulgebühren
Funktion aus der Oberklasse Student
wird von der übersteuert GraduateStudent
Klasse durch Hinzufügen der überschreiben
Modifikator vor dem Spaß
Stichwort. Wenn Sie ein Mitglied einer Superklasse oder Schnittstelle überschreiben, ist dies auch das überschreibende Member öffnen
standardmäßig wie im folgenden Beispiel:
Klasse ComputerScienceStudent: GraduateStudent () überschreibe fun schoolFees (): BigDecimal return super.schoolFees () + berechneSchoolFess () privater Spaß berechneSchoolFess (): BigDecimal // Schulgebühren berechnen und zurückgeben
Obwohl wir das nicht markiert haben Schulgebühren()
Methode in der GraduateStudent
Klasse mit der öffnen
Modifikator, wir können es immer noch überschreiben - wie wir es in der InformatikStudent
Klasse. Um dies zu verhindern, müssen wir das übergeordnete Mitglied als kennzeichnen Finale
.
Denken Sie daran, dass wir einer Klasse neue Funktionen hinzufügen können, auch wenn sie endgültig ist, indem Sie Erweiterungsfunktionen in Kotlin verwenden. Weitere Informationen zu den Erweiterungsfunktionen finden Sie unter Erweiterte Funktionen in Kotlin post. Wenn Sie darüber nachdenken müssen, wie Sie auch einer abschließenden Klasse neue Eigenschaften zuweisen können, ohne von ihr zu erben, lesen Sie den Abschnitt über die Erweiterungseigenschaften in meinem Beitrag Erweiterte Eigenschaften und Klassen.
Wenn unsere Superklasse einen primären Konstruktor wie folgt hat:
offene Klasse Student (Wert Vorname: Zeichenfolge, Wert Nachname: Zeichenfolge) //…
Dann muss jede Unterklasse den primären Konstruktor der Superklasse aufrufen.
Offene Klasse GraduateStudent (Vorname: Zeichenfolge, Nachname: Zeichenfolge): Student (Vorname, Nachname) //…
Wir können einfach ein Objekt von erstellen GraduateStudent
Unterricht wie gewohnt:
val graduateStudent = GraduateStudent ("Jon", "Snow") println (graduateStudent.firstName) // Jon
Wenn die Unterklasse den Superklassenkonstruktor von ihrem sekundären Konstruktor aufrufen möchte, verwenden wir die Super
Schlüsselwort (vergleichbar mit dem Aufruf von Superklasse-Konstruktoren in Java).
Offene Klasse GraduateStudent: Student //… private var thesis: String = "" Konstruktor (firstName: String, lastName: String, These: String): super (firstName, lastName) this.thesis = thesis
Wenn Sie eine Auffrischung der Klassenkonstruktoren in Kotlin benötigen, besuchen Sie bitte meine Klassen und Objekte.
Eine weitere tolle Sache, die wir in Kotlin tun können, ist, einem Typ einen Alias zu geben.
Lassen Sie uns ein Beispiel sehen.
Datenklasse Person (val firstName: String, val lastName: String, Wertalter: Int)
In der Klasse oben können wir die String
und Int
Typen für die Person
Eigenschaftenaliasnamen mit der Typealien
Modifikator in Kotlin. Mit diesem Modifikator können Sie einen Alias eines beliebigen Typs in Kotlin erstellen, einschließlich der von Ihnen erstellten.
typealias Name = Zeichenfolge typealias Alter = Int Datenklasse Person (Wert Vorname: Name, Wert Nachname: Name, Wert Alter: Alter)
Wie Sie sehen, haben wir einen Alias erstellt Name
und Alter
für beide die String
und Int
Typen. Wir haben das jetzt ersetzt Vorname
und Nachname
Eigenschaftstyp für unseren Alias Name
-und auch Int
tippen Sie auf Alter
alias. Beachten Sie, dass wir keine neuen Typen erstellt haben. Stattdessen haben wir einen Alias für die Typen erstellt.
Dies kann nützlich sein, wenn Sie den Typen in Ihrer Kotlin-Codebase eine bessere Bedeutung oder Semantik verleihen möchten. Also benutze sie weise!
In diesem Tutorial haben Sie mehr über objektorientierte Programmierung in Kotlin erfahren. Wir haben folgendes behandelt:
Wenn Sie Kotlin durch unsere Kotlin From Scratch-Serie gelernt haben, stellen Sie sicher, dass Sie den Code eingegeben haben, den Sie sehen, und ihn in Ihrer IDE ausführen. Ein guter Tipp, um eine neue Programmiersprache (oder ein anderes Programmierkonzept) zu verstehen, die Sie lernen, ist sicherzustellen, dass Sie nicht nur die Lernressource oder den Leitfaden lesen, sondern auch den eigentlichen Code eingeben und ausführen!
Im nächsten Tutorial der Kotlin From Scratch-Serie werden Sie mit der Ausnahmebehandlung in Kotlin vertraut gemacht. Bis bald!
Um mehr über die Kotlin-Sprache zu lernen, empfehle ich die Kotlin-Dokumentation. Auf Envato Tuts finden Sie auch einige unserer anderen Android-Apps zur Entwicklung von Apps!