Kotlin From Scratch Abstrakte Klassen, Schnittstellen, Vererbung und Typalias

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. 

1. Abstrakte Klassen

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

2. Schnittstellen

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:

  • Eine Klasse kann beliebig viele Schnittstellen implementieren, sie kann jedoch nur eine Klasse erweitern (ähnlich wie Java)..
  • Das überschreiben Modifier ist im Gegensatz zu Java in Kotlin obligatorisch. 
  • Neben Methoden können wir auch Eigenschaften in einer Kotlin-Schnittstelle deklarieren. 
  • Eine Kotlin-Schnittstellenmethode kann eine Standardimplementierung haben (ähnlich wie bei Java 8).. 

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! 

3. Vererbung

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. 

4. Bonus: Geben Sie einen Alias ​​ein

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! 

Fazit

In diesem Tutorial haben Sie mehr über objektorientierte Programmierung in Kotlin erfahren. Wir haben folgendes behandelt:

  • abstrakte Klassen
  • Schnittstellen 
  • Erbe
  • Geben Sie einen Alias ​​ein

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!