Kotlin Bootcamp für Programmers 4: Objektorientierte Programmierung

Dieses Codelab ist Teil des Kotlin-Bootcamps für Programmierer. Sie profitieren von diesem Kurs, wenn Sie nacheinander die Codelabs durcharbeiten. Abhängig von Ihrem Wissen können Sie möglicherweise einige Abschnitte überfliegen. Dieser Kurs richtet sich an Programmierer, die eine objektorientierte Sprache kennen und Kotlin lernen möchten.

Einführung

In diesem Codelab erstellen Sie ein Kotlin-Programm und erfahren mehr über Klassen und Objekte in Kotlin. Die meisten Inhalte sind Ihnen bekannt, wenn Sie eine andere objektorientierte Sprache kennen. Kotlin unterscheidet sich aber in einigen wichtigen Punkten, sodass Sie weniger Code schreiben müssen. Außerdem erfahren Sie mehr über abstrakte Klassen und die Delegierung von Benutzeroberflächen.

Anstatt eine einzige Beispiel-App zu entwickeln, sollten die Lektionen in diesem Kurs auf Ihrem Wissen aufbauen. Sie sind aber unabhängig und können die einzelnen Abschnitte überfliegen. In vielen Beispielen sehen Sie ein Aquarium. Wenn Sie die ganze Geschichte des Aquariums sehen möchten, sollten Sie sich den Kotlin Bootcamp für Programmers Udacity ansehen.

Was Sie bereits wissen sollten

  • Grundlagen von Kotlin, einschließlich Typen, Operatoren und Loopings
  • Syntax der Kotlin-Funktionen
  • Grundlagen der objektorientierten Programmierung
  • Grundlagen einer IDE wie IntelliJ IDEA oder Android Studio

Lerninhalte

  • In Kotlin Klassen erstellen und auf Properties zugreifen
  • Klassenkonstrukter in Kotlin erstellen und verwenden
  • Unterklasse erstellen und Funktionsweise der Übernahme
  • Abstrakte Klassen, Schnittstellen und Schnittstellendelegierung
  • Datenklassen erstellen und verwenden
  • Singleton-Werte, Aufzählungen und versiegelte Klassen verwenden

Aufgaben

  • Klasse mit Attributen erstellen
  • Konstruktor für eine Klasse erstellen
  • Unterklasse erstellen
  • Beispiele für abstrakte Klassen und Schnittstellen untersuchen
  • Einfache Datenklasse erstellen
  • Weitere Informationen zu Singleton- und Aufzählungslisten sowie zu versiegelten Klassen

Die folgenden Programmierkenntnisse sollten Ihnen bereits vertraut sein:

  • Klassen sind Baupläne für Objekte. Eine Aquarium-Klasse ist beispielsweise der Bauplan für ein Aquariumobjekt.
  • Objekte sind Instanzen von Klassen. Ein Aquariumobjekt ist ein tatsächlicher Aquarium.
  • Attribute sind Eigenschaften von Klassen, z. B. Länge, Breite und Höhe eines Aquarium.
  • Methoden, auch als Mitgliederfunktionen bezeichnet, sind die Funktionen der Klasse. Methoden können mit dem Objekt verwendet werden. Du kannst beispielsweise ein Aquarium-Objekt fillWithWater().
  • Eine Schnittstelle ist eine Spezifikation, die eine Klasse implementieren kann. Beispiel: Die Reinigung ist häufig für andere Objekte als Aquarien üblich. Die Reinigung erfolgt im Allgemeinen auf ähnliche Weise für verschiedene Objekte. So könnte eine Schnittstelle namens Clean die Definition einer clean()-Methode definieren. Mit der Klasse Aquarium kann die Schnittstelle Clean implementiert werden, um das Aquarium mit einem weichen Schwamm zu reinigen.
  • Pakete sind eine Möglichkeit, verwandten Code zu gruppieren, um ihn zu organisieren oder eine Codebibliothek zu erstellen. Nachdem ein Paket erstellt wurde, können Sie den Inhalt des Pakets in eine andere Datei importieren und den Code und die Klassen in diesem Paket wiederverwenden.

In dieser Aufgabe erstellen Sie ein neues Paket und eine Klasse mit einigen Attributen und einer Methode.

Schritt 1: Paket erstellen

Mit Paketen können Sie Ihren Code besser organisieren.

  1. Klicken Sie im Bereich Projekt unter dem Projekt Hello Kotlin mit der rechten Maustaste auf den Ordner src.
  2. Wähle New > Package aus und rufe es example.myapp auf.

Schritt 2: Klasse mit Properties erstellen

Klassen werden mit dem Keyword class definiert, wobei die Klassennamen per Konvention mit einem Großbuchstaben beginnen.

  1. Klicken Sie mit der rechten Maustaste auf das Paket example.myapp.
  2. Wähle Neu > Kotlin-Datei / Klasse aus.
  3. Wählen Sie unter Art die Option Kurs aus und nennen Sie die Klasse Aquarium. IntelliJ IDEA enthält den Paketnamen in der Datei und erstellt eine leere Aquarium-Klasse.
  4. Definieren und initialisieren Sie innerhalb der Aquarium-Klasse die var-Eigenschaften für Breite, Höhe und Länge (in Zentimetern). Initialisieren Sie die Eigenschaften mit Standardwerten.
package example.myapp

class Aquarium {
    var width: Int = 20
    var height: Int = 40
    var length: Int = 100
}

Im Hintergrund werden mit Kotlin automatisch Getter und Setter für die Properties erstellt, die Sie in der Aquarium-Klasse definiert haben. So können Sie direkt auf die Properties zugreifen, zum Beispiel „myAquarium.length“.

Schritt 3: „main()“-Funktion erstellen

Erstelle eine neue Datei mit dem Namen main.kt, die die Funktion main() enthalten soll.

  1. Klicken Sie links im Bereich Projekt mit der rechten Maustaste auf das Paket beispiel.meineapp.
  2. Wähle Neu > Kotlin-Datei / Klasse aus.
  3. Behalten Sie im Drop-down-Menü Art die Option Datei bei und benennen Sie die Datei main.kt. IntelliJ IDEA enthält den Paketnamen, aber keine Klassendefinition für eine Datei.
  4. Definieren Sie eine buildAquarium()-Funktion und erstellen Sie darin eine Instanz von Aquarium. Verweisen Sie zum Erstellen einer Instanz auf die Klasse, als wäre sie eine Funktion, Aquarium(). Dadurch wird der Konstruktor der Klasse aufgerufen und eine Instanz der Klasse Aquarium erstellt, ähnlich wie bei new in anderen Sprachen.
  5. Definiere eine main()-Funktion und rufe buildAquarium() auf.
package example.myapp

fun buildAquarium() {
    val myAquarium = Aquarium()
}

fun main() {
    buildAquarium()
}

Schritt 4: Methode hinzufügen

  1. Fügen Sie in der Klasse Aquarium eine Methode hinzu, um die Eigenschaften des Aquariums zu drucken.
    fun printSize() {
        println("Width: $width cm " +
                "Length: $length cm " +
                "Height: $height cm ")
    }
  1. Rufe in main.kt in buildAquarium() die Methode printSize() für myAquarium auf.
fun buildAquarium() {
    val myAquarium = Aquarium()
    myAquarium.printSize()
}
  1. Führe dein Programm aus, indem du auf das grüne Dreieck neben der Funktion main() klickst. Beobachten Sie das Ergebnis.
⇒ Width: 20 cm Length: 100 cm Height: 40 cm 
  1. Fügen Sie in buildAquarium() Code hinzu, um die Höhe auf 60 festzulegen und die geänderten Dimensionseigenschaften zu drucken.
fun buildAquarium() {
    val myAquarium = Aquarium()
    myAquarium.printSize()
    myAquarium.height = 60
    myAquarium.printSize()
}
  1. Führen Sie Ihr Programm aus und beobachten Sie die Ausgabe.
⇒ Width: 20 cm Length: 100 cm Height: 40 cm 
Width: 20 cm Length: 100 cm Height: 60 cm 

In dieser Aufgabe erstellen Sie einen Konstruktor für die Klasse und arbeiten weiter mit Attributen.

Schritt 1: Konstruktor erstellen

In diesem Schritt fügen Sie der Klasse Aquarium, die Sie in der ersten Aufgabe erstellt haben, einen Konstruktor hinzu. Im vorherigen Beispiel wird jede Instanz von Aquarium mit denselben Dimensionen erstellt. Sie können die Größe nach der Erstellung ändern, indem Sie die Eigenschaften festlegen. Es ist aber einfacher, sie erst einmal mit der richtigen Größe zu erstellen.

In einigen Programmiersprachen wird der Konstruktor durch Erstellen einer Methode innerhalb der Klasse definiert, die denselben Namen wie die Klasse hat. In Kotlin definieren Sie den Konstruktor direkt in der Klassendeklaration. Geben Sie die Parameter in Klammern an, als ob die Klasse eine Methode wäre. Wie bei Funktionen in Kotlin können diese Parameter Standardwerte enthalten.

  1. Ändern Sie in der zuvor erstellten Klasse Aquarium die Klassendefinition, sodass drei Konstruktorparameter mit den Standardwerten für length, width und height enthalten sind. Ordnen Sie sie den entsprechenden Properties zu.
class Aquarium(length: Int = 100, width: Int = 20, height: Int = 40) {
   // Dimensions in cm
   var length: Int = length
   var width: Int = width
   var height: Int = height
...
}
  1. Bei der kompakteren Kotlin-Definition können Sie die Eigenschaften mithilfe von var oder val direkt mit dem Konstruktor definieren. Kotlin erstellt auch die Getter und Setter automatisch. Anschließend können Sie die Property-Definitionen im Hauptbereich der Klasse entfernen.
class Aquarium(var length: Int = 100, var width: Int = 20, var height: Int = 40) {
...
}
  1. Wenn Sie ein Aquarium-Objekt mit diesem Konstruktor erstellen, können Sie keine Argumente angeben und die Standardwerte abrufen oder nur einige davon festlegen oder alle festlegen und ein Aquarium mit einer benutzerdefinierten Größe erstellen. Probieren Sie in der buildAquarium()-Funktion verschiedene Möglichkeiten zum Erstellen eines Aquarium-Objekts mit benannten Parametern aus.
fun buildAquarium() {
    val aquarium1 = Aquarium()
    aquarium1.printSize()
    // default height and length
    val aquarium2 = Aquarium(width = 25)
    aquarium2.printSize()
    // default width
    val aquarium3 = Aquarium(height = 35, length = 110)
    aquarium3.printSize()
    // everything custom
    val aquarium4 = Aquarium(width = 25, height = 35, length = 110)
    aquarium4.printSize()
}
  1. Führen Sie das Programm aus und beobachten Sie die Ausgabe.
⇒ Width: 20 cm Length: 100 cm Height: 40 cm 
Width: 25 cm Length: 100 cm Height: 40 cm 
Width: 20 cm Length: 110 cm Height: 35 cm 
Width: 25 cm Length: 110 cm Height: 35 cm 

Sie mussten den Konstruktor nicht überlasten und für jeden dieser Fälle eine andere Version erstellen (für die anderen Kombinationen einige mehr). Kotlin erstellt die erforderlichen Werte aus den Standardwerten und benannten Parametern.

Schritt 2: Sperrblöcke hinzufügen

In den Beispielkonstrukten oben werden nur Eigenschaften deklariert und den Werten eines Ausdrucks zugewiesen. Wenn Ihr Konstruktor mehr Initialisierungscode benötigt, kann er in einem oder mehreren init-Blöcken platziert werden. In diesem Schritt fügen Sie der Klasse Aquarium einige init-Blöcke hinzu.

  1. Fügen Sie in der Klasse Aquarium einen init-Block hinzu, damit das Objekt initialisiert wird, und einen zweiten Block, um das Volumen in Liter zu drucken.
class Aquarium (var length: Int = 100, var width: Int = 20, var height: Int = 40) {
    init {
        println("aquarium initializing")
    }
    init {
        // 1 liter = 1000 cm^3
        println("Volume: ${width * length * height / 1000} l")
    }
}
  1. Führen Sie das Programm aus und beobachten Sie die Ausgabe.
aquarium initializing
Volume: 80 l
Width: 20 cm Length: 100 cm Height: 40 cm 
aquarium initializing
Volume: 100 l
Width: 25 cm Length: 100 cm Height: 40 cm 
aquarium initializing
Volume: 77 l
Width: 20 cm Length: 110 cm Height: 35 cm 
aquarium initializing
Volume: 96 l
Width: 25 cm Length: 110 cm Height: 35 cm 

Beachten Sie, dass die init-Blöcke in der Reihenfolge ausgeführt werden, in der sie in der Klassendefinition aufgeführt sind. Alle Blöcke werden ausgeführt, wenn der Konstruktor aufgerufen wird.

Schritt 3: Informationen zu sekundären Konstruktoren

In diesem Schritt erfahren Sie mehr über sekundäre Konstruktoren und fügen Ihrer Klasse einen hinzu. Neben einem primären Konstruktor, der einen oder mehrere init-Blöcke haben kann, kann eine Kotlin-Klasse auch einen oder mehrere sekundäre Konstruktoren haben, um eine Konstruktorüberlastung zu ermöglichen.

  1. Füge in der Klasse Aquarium einen sekundären Konstruktor hinzu, der mit dem Schlüsselwort constructor eine Reihe von Fischen als Argument verwendet. Erstellen Sie eine val-Tankeigenschaft für das berechnete Volumen des Aquariums in Liter basierend auf der Anzahl der Fische. Nimm 2 Liter Wasser (2.000 cm^3) Wasser pro Fisch sowie ein wenig Extraraum ein, damit das Wasser nicht verschüttet wird.
constructor(numberOfFish: Int) : this() {
    // 2,000 cm^3 per fish + extra room so water doesn't spill
    val tank = numberOfFish * 2000 * 1.1
}
  1. Behalten Sie im sekundären Konstruktor die Länge und Breite (im primären Konstruktor) bei und berechnen Sie die Höhe, die für das Erstellen des Tanks erforderlich ist.
    // calculate the height needed
    height = (tank / (length * width)).toInt()
  1. Fügen Sie in der Funktion buildAquarium() einen Aufruf zum Erstellen einer Aquarium mit Ihrem neuen sekundären Konstruktor ein. Größe und Volumen drucken
fun buildAquarium() {
    val aquarium6 = Aquarium(numberOfFish = 29)
    aquarium6.printSize()
    println("Volume: ${aquarium6.width * aquarium6.length * aquarium6.height / 1000} l")
}
  1. Führen Sie Ihr Programm aus und beobachten Sie die Ausgabe.
⇒ aquarium initializing
Volume: 80 l
Width: 20 cm Length: 100 cm Height: 31 cm 
Volume: 62 l

Beachten Sie, dass das Volume zweimal gedruckt wird: einmal durch den init-Block im primären Konstruktor und vor der Ausführung des sekundären Konstruktors und einmal durch den Code in buildAquarium().

Du könntest auch das Keyword constructor in den primären Konstruktor aufnehmen, aber es ist in den meisten Fällen nicht erforderlich.

Schritt 4: neuen Property Getter hinzufügen

In diesem Schritt fügen Sie einen expliziten Property-Getter hinzu. Wenn Sie Eigenschaften definieren, werden mit Kotlin automatisch Getter und Setter definiert. Manchmal muss jedoch der Wert für eine Eigenschaft angepasst oder berechnet werden. Oben haben Sie z. B. das Volumen von Aquarium gedruckt. Sie können das Volumen als Property verfügbar machen, indem Sie eine Variable und einen Getter dafür definieren. Da volume berechnet werden muss, muss der Getter den berechneten Wert zurückgeben. Sie können ihn dazu mit einer einzeiligen Funktion verwenden.

  1. Definieren Sie in der Klasse Aquarium eine Int-Property mit dem Namen volume und definieren Sie eine get()-Methode, mit der das Volumen in der nächsten Zeile berechnet wird.
val volume: Int
    get() = width * height * length / 1000  // 1000 cm^3 = 1 l
  1. Entfernen Sie den init-Block, der die Lautstärke druckt.
  2. Entfernen Sie den Code in buildAquarium(), der die Lautstärke druckt.
  3. Fügen Sie in der Methode printSize() eine Zeile hinzu, um das Volumen zu drucken.
fun printSize() {
    println("Width: $width cm " +
            "Length: $length cm " +
            "Height: $height cm "
    )
    // 1 l = 1000 cm^3
    println("Volume: $volume l")
}
  1. Führen Sie Ihr Programm aus und beobachten Sie die Ausgabe.
⇒ aquarium initializing
Width: 20 cm Length: 100 cm Height: 31 cm 
Volume: 62 l

Die Dimensionen und Volumes sind wie zuvor, aber das Volume wird nur einmal gedruckt, nachdem das Objekt sowohl vom primären als auch vom sekundären Konstruktor vollständig initialisiert wurde.

Schritt 5: Property-Setter hinzufügen

In diesem Schritt erstellen Sie einen neuen Property-Setter für das Volume.

  1. Ändern Sie den volume in der Aquarium-Klasse in einen var-Wert, damit er mehrmals festgelegt werden kann.
  2. Fügen Sie einen Setter für die Property volume hinzu. Fügen Sie dazu unter dem Getter eine set()-Methode hinzu, die die Höhe basierend auf der angegebenen Wassermenge neu berechnet. Der Name des Setter-Parameters ist standardmäßig value, Sie können ihn aber ändern.
var volume: Int
    get() = width * height * length / 1000
    set(value) {
        height = (value * 1000) / (width * length)
    }
  1. Fügen Sie in buildAquarium() Code hinzu, um die Lautstärke des Aquariums auf 70 Liter festzulegen. Die neue Größe drucken.
fun buildAquarium() {
    val aquarium6 = Aquarium(numberOfFish = 29)
    aquarium6.printSize()
    aquarium6.volume = 70
    aquarium6.printSize()
}
  1. Führen Sie Ihr Programm noch einmal aus und beobachten Sie die geänderte Höhe und Lautstärke.
⇒ aquarium initialized
Width: 20 cm Length: 100 cm Height: 31 cm 
Volume: 62 l
Width: 20 cm Length: 100 cm Height: 35 cm 
Volume: 70 l

Im Code gab es bislang keine Modifizierer für die Sichtbarkeit wie public oder private. Da in Kotlin standardmäßig alles öffentlich ist, können Sie von überall aus darauf zugreifen, einschließlich der Klassen, Methoden, Properties und Mitgliedsvariablen.

In Kotlin können Klassen, Objekte, Schnittstellen, Konstruktoren, Funktionen, Properties und deren Setter Sichtbarkeitsmodifikatoren haben:

  • public bedeutet, dass Teilnehmer außerhalb der Klasse sichtbar sind. Alle sind standardmäßig öffentlich, einschließlich Variablen und Methoden der Klasse.
  • internal bedeutet, dass die Datei nur in diesem Modul sichtbar ist. Ein Modul besteht aus mehreren Kotlin-Dateien, die zusammen zusammengestellt wurden, zum Beispiel aus einer Bibliothek oder Anwendung.
  • private bedeutet, dass es nur in dieser Klasse (oder Quelldateien, wenn Sie mit Funktionen arbeiten) sichtbar ist.
  • protected ist identisch mit private, ist aber auch für alle Unterklassen sichtbar.

Weitere Informationen finden Sie in der Kotlin-Dokumentation unter Sichtbarkeitsmodifikatoren.

Mitgliedervariablen

Eigenschaften in einer Klasse oder Mitgliedervariablen sind standardmäßig public. Wenn Sie sie mit var definieren, können sie geändert werden, sind also lesbar und beschreibbar. Wenn Sie sie mit val definieren, sind sie nach der Initialisierung schreibgeschützt.

Wenn Sie eine Property haben, die im Code gelesen oder geschrieben werden kann, während eine externe URL nur Lesevorgänge unterstützt, können Sie die Property und den zugehörigen Getter als öffentlich belassen und den Setter auf „privat“ setzen, wie unten dargestellt.

var volume: Int
    get() = width * height * length / 1000
    private set(value) {
        height = (value * 1000) / (width * length)
    }

In dieser Aufgabe lernen Sie, wie Unterklassen und Übernahmen in Kotlin funktionieren. Sie ähneln denen, die du in anderen Sprachen gesehen hast, es gibt aber einige Unterschiede.

In Kotlin können Klassen standardmäßig keine Unterklassen erstellen. Ebenso können Properties und Mitgliedervariablen nicht von Unterklassen überschrieben werden, auf sie kann jedoch zugegriffen werden.

Sie müssen eine Klasse als open kennzeichnen, damit sie abgeleitet werden kann. Ebenso müssen Sie Attribute und Mitgliedsvariablen als open markieren, um sie in der Unterklasse zu überschreiben. Das Keyword open ist erforderlich, um zu vermeiden, dass Daten im Rahmen der Implementierung versehentlich zu Details gelangen.

Schritt 1: Aquarium-Kurs öffnen

In diesem Schritt machen Sie die Aquarium-Klasse open, sodass Sie sie im nächsten Schritt überschreiben können.

  1. Markiere die Klasse Aquarium und alle ihre Eigenschaften mit dem Keyword open.
open class Aquarium (open var length: Int = 100, open var width: Int = 20, open var height: Int = 40) {
    open var volume: Int
        get() = width * height * length / 1000
        set(value) {
            height = (value * 1000) / (width * length)
        }
  1. Fügen Sie eine offene shape-Property mit dem Wert "rectangle" hinzu.
   open val shape = "rectangle"
  1. Füge eine offene water-Property mit einem Getter hinzu, der 90% des Volumens von Aquarium zurückgibt.
    open var water: Double = 0.0
        get() = volume * 0.9
  1. Füge der Methode printSize() Code hinzu, um die Form und die Wassermenge als Prozentsatz des Volumens zu drucken.
fun printSize() {
    println(shape)
    println("Width: $width cm " +
            "Length: $length cm " +
            "Height: $height cm ")
    // 1 l = 1000 cm^3
    println("Volume: $volume l Water: $water l (${water/volume*100.0}% full)")
}
  1. Ändern Sie in buildAquarium() den Code, um einen Aquarium mit width = 25, length = 25 und height = 40 zu erstellen.
fun buildAquarium() {
    val aquarium6 = Aquarium(length = 25, width = 25, height = 40)
    aquarium6.printSize()
}
  1. Führen Sie Ihr Programm aus und beobachten Sie die neue Ausgabe.
⇒ aquarium initializing
rectangle
Width: 25 cm Length: 25 cm Height: 40 cm 
Volume: 25 l Water: 22.5 l (90.0% full)

Schritt 2: Unterklasse erstellen

  1. Erstellen Sie eine Unterklasse von Aquarium namens TowerTank, die einen abgerundeten Zylinderbehälter anstelle eines rechteckigen Behälters implementiert. Sie können TowerTank unter Aquarium hinzufügen, da Sie eine weitere Klasse in derselben Datei wie die Aquarium-Klasse hinzufügen.
  2. Überschreiben Sie in TowerTank die Property height, die im Konstruktor definiert ist. Wenn du eine Property überschreiben möchtest, verwende das Keyword override in der Unterklasse.
  1. Machen Sie den Konstruktor für TowerTank zu einer diameter. Verwende diameter für length und width beim Aufrufen des Konstruktors in der Aquarium-Superclass.
class TowerTank (override var height: Int, var diameter: Int): Aquarium(height = height, width = diameter, length = diameter) {
  1. Überschreiben Sie die Lautstärke-Property, um einen Zylinder zu berechnen. Die Formel für einen Zylinder ist Pi mal Quadrat des Radius mal die Höhe. Sie müssen die Konstante PI aus java.lang.Math importieren.
    override var volume: Int
    // ellipse area = π * r1 * r2
    get() = (width/2 * length/2 * height / 1000 * PI).toInt()
    set(value) {
        height = ((value * 1000 / PI) / (width/2 * length/2)).toInt()
    }
  1. Überschreibe in TowerTank das Attribut water auf 80% des Volumens.
override var water = volume * 0.8
  1. Überschreibe die Datei shape, um "cylinder".
override val shape = "cylinder"
  1. Ihre endgültige TowerTank-Klasse sollte in etwa so aussehen:

Aquarium.kt:

package example.myapp

import java.lang.Math.PI

... // existing Aquarium class

class TowerTank (override var height: Int, var diameter: Int): Aquarium(height = height, width = diameter, length = diameter) {
    override var volume: Int
    // ellipse area = π * r1 * r2
    get() = (width/2 * length/2 * height / 1000 * PI).toInt()
    set(value) {
        height = ((value * 1000 / PI) / (width/2 * length/2)).toInt()
    }

    override var water = volume * 0.8
    override val shape = "cylinder"
}
  1. Erstellen Sie in buildAquarium() einen TowerTank mit einem Durchmesser von 25 cm und einer Höhe von 45 cm. Drucken Sie das Format aus.

main.kt:

package example.myapp

fun buildAquarium() {
    val myAquarium = Aquarium(width = 25, length = 25, height = 40)
    myAquarium.printSize()
    val myTower = TowerTank(diameter = 25, height = 40)
    myTower.printSize()
}
  1. Führen Sie Ihr Programm aus und beobachten Sie die Ausgabe.
⇒ aquarium initializing
rectangle
Width: 25 cm Length: 25 cm Height: 40 cm 
Volume: 25 l Water: 22.5 l (90.0% full)
aquarium initializing
cylinder
Width: 25 cm Length: 25 cm Height: 40 cm 
Volume: 18 l Water: 14.4 l (80.0% full)

Manchmal möchten Sie gemeinsame Verhaltensweisen oder Eigenschaften definieren, die von verschiedenen zugehörigen Klassen gemeinsam genutzt werden können. Kotlin bietet hierfür zwei Möglichkeiten: Schnittstellen und abstrakte Klassen. In dieser Aufgabe erstellen Sie eine abstrakte AquariumFish-Klasse für alle Properties, die für alle Fische gelten. Sie erstellen die Benutzeroberfläche FishAction, um die Funktionsweise aller Fische zu definieren.

  • Weder eine abstrakte Klasse noch eine Schnittstelle kann allein instanziiert werden. Das bedeutet, dass Sie keine Objekte dieser Typen direkt erstellen können.
  • Abstrakte Klassen haben Konstruktoren.
  • Schnittstellen können keine Konstruktorlogik haben oder einen beliebigen Status speichern.

Schritt 1: Abstrakte Klasse erstellen

  1. Erstellen Sie unter beispiel.meineapp die neue Datei AquariumFish.kt.
  2. Erstelle eine Klasse mit dem Namen AquariumFish und markiere sie mit abstract.
  3. Füge eine String-Property (color) hinzu und markiere sie mit abstract.
package example.myapp

abstract class AquariumFish {
    abstract val color: String
}
  1. Erstelle zwei Unterklassen von AquariumFish, Shark und Plecostomus.
  2. Da color abstrakt ist, müssen die Unterklassen sie implementieren. Shark wird grau und Plecostomus Gold.
class Shark: AquariumFish() {
    override val color = "gray"
}

class Plecostomus: AquariumFish() {
    override val color = "gold"
}
  1. Erstellen Sie in main.kt eine makeFish()-Funktion, um Ihre Kurse zu testen. Instanziiere einen Shark und einen Plecostomus und drucke dann die Farbe jeder davon aus.
  2. Löschen Sie Ihren vorherigen Testcode in main() und fügen Sie makeFish() einen Aufruf hinzu. Der Code sollte in etwa so aussehen:

main.kt:

package example.myapp

fun makeFish() {
    val shark = Shark()
    val pleco = Plecostomus()

    println("Shark: ${shark.color}")
    println("Plecostomus: ${pleco.color}")
}

fun main () {
    makeFish()
}
  1. Führen Sie Ihr Programm aus und beobachten Sie die Ausgabe.
⇒ Shark: gray 
Plecostomus: gold

Das folgende Diagramm stellt die Klasse Shark und die Klasse Plecostomus dar, die die abstrakte Klasse AquariumFish darstellt.

Ein Diagramm, in dem die abstrakte Klasse AquariumFish und zwei Unterklassen, Shark und Plecostumus dargestellt werden.

Schritt 2: Benutzeroberfläche erstellen

  1. Erstellen Sie in AquariumFish.kt eine Schnittstelle namens FishAction mit der Methode eat().
interface FishAction  {
    fun eat()
}
  1. Füge jeder Unterklasse FishAction hinzu und implementiere eat(), indem du sie ausgibst, was die Fische tun sollen.
class Shark: AquariumFish(), FishAction {
    override val color = "gray"
    override fun eat() {
        println("hunt and eat fish")
    }
}

class Plecostomus: AquariumFish(), FishAction {
    override val color = "gold"
    override fun eat() {
        println("eat algae")
    }
}
  1. Mit der makeFish()Funktion können Sie alle Fische, die Sie erstellt haben, durch Aufrufen von eat() ernähren.
fun makeFish() {
    val shark = Shark()
    val pleco = Plecostomus()
    println("Shark: ${shark.color}")
    shark.eat()
    println("Plecostomus: ${pleco.color}")
    pleco.eat()
}
  1. Führen Sie Ihr Programm aus und beobachten Sie die Ausgabe.
⇒ Shark: gray
hunt and eat fish
Plecostomus: gold
eat algae

Das folgende Diagramm zeigt die Klasse Shark und die Klasse Plecostomus, die beide aus der Schnittstelle FishAction bestehen und implementiert.

Abstrakte Klassen und Schnittstellen verwenden

Die oben genannten Beispiele sind einfach. Aber wenn Sie viele miteinander verbundene Kurse haben, können Sie mithilfe abstrakter Kurse und Benutzeroberflächen Ihr Design sauberer, besser organisieren und einfacher verwalten.

Wie oben erwähnt, können abstrakte Klassen Konstruktoren haben, Schnittstellen können das nicht, ansonsten sind sie sich aber sehr ähnlich. Wann sollten Sie die beiden verwenden?

Wenn Sie Schnittstellen verwenden, um eine Klasse zu erstellen, wird die Funktionalität der Klasse durch die enthaltenen Klasseninstanzen erweitert. Kompositionen erleichtern in der Regel die Wiederverwendung und den Grund dafür, dass sie aus einer abstrakten Klasse übernommen werden können. Sie können in einer Klasse auch mehrere Schnittstellen verwenden, allerdings nur Unterklassen aus einer abstrakten Klasse.

Die Zusammensetzung führt häufig zu einer besseren Kapselung, einer geringeren Kopplung (Interdependenz), einfacheren Schnittstellen und einem besser nutzbaren Code. Aus diesen Gründen wird die Verwendung von Kompositionen mit Schnittstellen bevorzugt. Andererseits ist die Übernahme von einer abstrakten Klasse in der Regel eine natürliche Lösung für einige Probleme. Sie sollten also die Komposition bevorzugen, aber wenn die Übernahme Sinn macht, können Sie das auch mit Kotlin tun.

  • Wenn du viele Methoden und eine oder zwei Standardimplementierungen hast, solltest du eine Schnittstelle verwenden, wie in AquariumAction unten dargestellt.
interface AquariumAction {
    fun eat()
    fun jump()
    fun clean()
    fun catchFish()
    fun swim()  {
        println("swim")
    }
}
  • Abstrakte Kurse sind immer dann möglich, wenn Sie einen Kurs abgeschlossen haben. Du kannst beispielsweise zur AquariumFish-Klasse zurückkehren und die gesamte AquariumFish-Implementierung auf FishAction anwenden. Außerdem hast du die Möglichkeit, eine Standardimplementierung für eat zu implementieren und gleichzeitig die abstrakte Version color beizubehalten, da es tatsächlich eine Standardfarbe für Fisch gibt.
interface FishAction  {
    fun eat()
}

abstract class AquariumFish: FishAction {
   abstract val color: String
   override fun eat() = println("yum")
}

Bei der vorherigen Aufgabe wurden abstrakte Klassen, Benutzeroberflächen und die Idee des Erstellens vorgestellt. Die Schnittstellendelegierung ist eine fortgeschrittene Methode, bei der die Methoden einer Schnittstelle von einem Hilfsobjekt (oder Bevollmächtigten) implementiert werden, das dann von einer Klasse verwendet wird. Das ist nützlich, wenn Sie eine Schnittstelle in einer Reihe unabhängiger Klassen verwenden: Sie fügen die erforderlichen Schnittstellenfunktionen einer separaten Hilfsklasse hinzu, und jede der Klassen verwendet eine Instanz der Hilfsklasse, um die Funktion zu implementieren.

In dieser Aufgabe verwenden Sie die Delegierung der Benutzeroberfläche, um einer Klasse Funktionen hinzuzufügen.

Schritt 1: Neue Benutzeroberfläche erstellen

  1. Entfernen Sie die Klasse AquariumFish in AquariumFish.kt. Anstatt Elemente aus der AquariumFish-Klasse zu übernehmen, implementieren Plecostomus und Shark Schnittstellen für die Fischaktion und die jeweilige Farbe.
  2. Erstellen Sie eine neue Schnittstelle, FishColor, mit der die Farbe als String definiert wird.
interface FishColor {
    val color: String
}
  1. Ändern Sie Plecostomus, um die beiden Schnittstellen FishAction und FishColor zu implementieren. Du musst color aus FishColor und eat() aus FishAction überschreiben.
class Plecostomus: FishAction, FishColor {
    override val color = "gold"
    override fun eat() {
        println("eat algae")
    }
}
  1. Ändern Sie Ihre Shark-Klasse, um auch die beiden Schnittstellen FishAction und FishColor zu implementieren, anstatt sie von AquariumFish zu übernehmen.
class Shark: FishAction, FishColor {
    override val color = "gray"
    override fun eat() {
        println("hunt and eat fish")
    }
}
  1. Der fertige Code sollte in etwa so aussehen:
package example.myapp

interface FishAction {
    fun eat()
}

interface FishColor {
    val color: String
}

class Plecostomus: FishAction, FishColor {
    override val color = "gold"
    override fun eat() {
        println("eat algae")
    }
}

class Shark: FishAction, FishColor {
    override val color = "gray"
    override fun eat() {
        println("hunt and eat fish")
    }
}

Schritt 2: Singleton-Kurs erstellen

Als Nächstes implementieren Sie die Einrichtung für den Delegierungsteil, indem Sie eine Hilfsklasse erstellen, die FishColor implementiert. Sie erstellen die Grundklasse GoldColor, mit der FishColor implementiert wird. Sie wird lediglich als Gold bezeichnet.

Es ist nicht sinnvoll, mehrere Instanzen von GoldColor zu erstellen, da diese Aktionen genau das Gleiche bewirken. Mit Kotlin können Sie also eine Klasse deklarieren, bei der Sie nur eine Instanz davon erstellen können. Nutzen Sie dazu das Keyword object statt class. Diese wird von Kotlin erstellt und durch den Klassennamen verwiesen. Alle anderen Objekte können anschließend nur diese eine Instanz verwenden – es ist nicht möglich, andere Instanzen dieser Klasse zu erstellen. Wenn Sie mit dem Singleton-Muster vertraut sind, erfahren Sie, wie Sie Singleton-Modelle in Kotlin implementieren.

  1. Erstelle in AquariumFish.kt ein Objekt für GoldColor. Die Farbe wird überschrieben.
object GoldColor : FishColor {
   override val color = "gold"
}

Schritt 3: Schnittstellendelegierung für FishColor hinzufügen

Sie können jetzt die Delegierung der Benutzeroberfläche verwenden.

  1. Entfernen Sie in AquariumFish.kt die Überschreibung von color aus Plecostomus.
  2. Ändern Sie die Klasse Plecostomus, um ihre Farbe aus GoldColor zu erhalten. Fügen Sie dazu by GoldColor in die Klassendeklaration ein und erstellen Sie die Delegierung. Das bedeutet, dass anstelle der Implementierung von FishColor die von GoldColor bereitgestellte Implementierung verwendet wird. Jedes Mal, wenn auf color zugegriffen wird, wird die Instanz an GoldColor delegiert.
class Plecostomus:  FishAction, FishColor by GoldColor {
   override fun eat() {
       println("eat algae")
   }
}

Dabei sind alle Plecos golden, aber diese Fische sind in vielen Farben erhältlich. Sie können das Problem beheben, indem Sie den Konstruktorparameter für die Farbe hinzufügen. Dabei steht GoldColor als Standardfarbe für Plecostomus.

  1. Ändern Sie die Klasse Plecostomus so, dass eine fishColor in ihrem Konstruktor übergeben wird, und legen Sie den Standardwert auf GoldColor fest. Ändern Sie die Delegierung von by GoldColor zu by fishColor.
class Plecostomus(fishColor: FishColor = GoldColor):  FishAction,
       FishColor by fishColor {
   override fun eat() {
       println("eat algae")
   }
}

Schritt 4: Schnittstellendelegierung für FishAction hinzufügen

Ebenso kannst du die Schnittstellendelegierung für FishAction verwenden.

  1. Erstellen Sie in AquariumFish.kt eine PrintingFishAction-Klasse, die FishAction implementiert, wodurch String und food verwendet werden und dann gedruckt wird, was die Fische essen.
class PrintingFishAction(val food: String) : FishAction {
    override fun eat() {
        println(food)
    }
}
  1. Entfernen Sie in der Plecostomus-Klasse die Überschreibungsfunktion eat(), da Sie sie durch eine Delegierung ersetzen.
  2. Geben Sie in der Deklaration von Plecostomus FishAction an PrintingFishAction weiter, um "eat algae" zu übergeben.
  3. Bei dieser Delegierung gibt es keinen Code im Text der Plecostomus-Klasse. Entfernen Sie daher {}, da alle Überschreibungen von der Schnittstellendelegierung verarbeitet werden
class Plecostomus (fishColor: FishColor = GoldColor):
        FishAction by PrintingFishAction("eat algae"),
        FishColor by fishColor

Das folgende Diagramm zeigt die Klassen Shark und Plecostomus, die beide aus den Schnittstellen PrintingFishAction und FishColor bestehen, aber die Implementierung an sie delegieren.

Die Delegierung der Benutzeroberfläche ist leistungsfähig. Wenn Sie eine abstrakte Klasse in einer anderen Sprache nutzen, sollten Sie sich daher überlegen, wie Sie sie einsetzen können. Sie haben die Möglichkeit, die Zusammensetzung zum Starten von Verhaltensweisen zu verwenden, anstatt viele Unterklassen zu konfigurieren, die jeweils unterschiedlich sind.

Eine Datenklasse ähnelt einem struct-Objekt in einigen anderen Sprachen – sie besteht hauptsächlich aus Daten, doch ein Datenklassenobjekt ist weiterhin ein Objekt. Kotlin-Datenklassenobjekte bieten zusätzliche Vorteile, z. B. Dienstprogramme für das Drucken und Kopieren. In dieser Aufgabe erstellen Sie eine einfache Datenklasse und erfahren, welche Unterstützung Kotlin für Datenklassen bietet.

Schritt 1: Datenklasse erstellen

  1. Fügen Sie unter dem Paket example.myapp das neue Paket decor hinzu, das den neuen Code enthalten soll. Klicken Sie im Bereich Projekt mit der rechten Maustaste auf beispiel.meineapp und wählen Sie Datei > Neues > Paket aus.
  2. Erstellen Sie im Paket eine neue Klasse namens Decoration.
package example.myapp.decor

class Decoration {
}
  1. Wenn Decoration eine Datenklasse sein soll, stellen Sie der Klassendeklaration das Keyword data voran.
  2. Füge der Property String eine Property mit dem Namen rocks hinzu, damit die Klasse Daten erhält.
data class Decoration(val rocks: String) {
}
  1. Fügen Sie in der Datei außerhalb der Klasse eine makeDecorations()-Funktion hinzu, um eine Instanz von Decoration mit "granite" zu erstellen und zu drucken.
fun makeDecorations() {
    val decoration1 = Decoration("granite")
    println(decoration1)
}
  1. Fügen Sie eine main()-Funktion hinzu, um makeDecorations() aufzurufen und das Programm auszuführen. Sie sehen nun die sinnvolle Ausgabe, die erstellt wird, da es sich um eine Datenklasse handelt.
⇒ Decoration(rocks=granite)
  1. In makeDecorations() instanziieren Sie zwei weitere Decoration-Objekte, die beide &slatiert sind und drucken.
fun makeDecorations() {
    val decoration1 = Decoration("granite")
    println(decoration1)

    val decoration2 = Decoration("slate")
    println(decoration2)

    val decoration3 = Decoration("slate")
    println(decoration3)
}
  1. Fügen Sie in makeDecorations() eine Druckausgabe hinzu, in der das Ergebnis des Vergleichs von decoration1 mit decoration2 und eines zweiten die Ergebnisse von decoration3 mit decoration2 gedruckt werden. Verwenden Sie die von Datenklassen bereitgestellte Methode „Equals()“.
    println (decoration1.equals(decoration2))
    println (decoration3.equals(decoration2))
  1. Führen Sie den Code aus.
⇒ Decoration(rocks=granite)
Decoration(rocks=slate)
Decoration(rocks=slate)
false
true

Schritt 2: Zerstörende Elemente verwenden

Wenn Sie die Eigenschaften eines Datenobjekts abrufen und Variablen zuweisen möchten, können Sie sie einzeln zuweisen.

val rock = decoration.rock
val wood = decoration.wood
val diver = decoration.diver

Stattdessen können Sie Variablen erstellen, eine für jede Property, und das Datenobjekt der Variablengruppe zuweisen. Kotlin fügt den Property-Wert in jede Variable ein.

val (rock, wood, diver) = decoration

Dieser Begriff wird als Zerstörung bezeichnet und ist ein nützliches Kurzbefehl. Die Anzahl der Variablen sollte der Anzahl der Eigenschaften entsprechen und in der Reihenfolge zugewiesen werden, in der sie in der Klasse deklariert werden. Hier finden Sie ein vollständiges Beispiel für Decoration.kt.

// Here is a data class with 3 properties.
data class Decoration2(val rocks: String, val wood: String, val diver: String){
}

fun makeDecorations() {
    val d5 = Decoration2("crystal", "wood", "diver")
    println(d5)

// Assign all properties to variables.
    val (rock, wood, diver) = d5
    println(rock)
    println(wood)
    println(diver)
}
⇒ Decoration2(rocks=crystal, wood=wood, diver=diver)
crystal
wood
diver

Wenn du eine oder mehrere Properties nicht benötigst, kannst du sie mit _ anstelle des Variablennamens überspringen, wie im Code unten zu sehen ist.

    val (rock, _, diver) = d5

In dieser Aufgabe lernen Sie einige der Spezialklassen in Kotlin kennen, darunter:

  • Singleton-Kurse
  • Enums
  • Versiegelte Kurse

Schritt 1: Singleton-Klassen wiederholen

Rufen Sie das vorherige Beispiel mit der Klasse GoldColor auf.

object GoldColor : FishColor {
   override val color = "gold"
}

Da jede Instanz von GoldColor dasselbe macht, wird sie als object anstelle von class deklariert, um sie zu einem Singleton zu machen. Es kann nur einmal vorkommen.

Schritt 2: Aufzählung erstellen

Kotlin unterstützt auch Aufzählungen. Damit können Sie etwas aufzählen und darauf verweisen, ähnlich wie in anderen Sprachen. Deklarieren Sie eine Aufzählung, indem Sie der Deklaration das Keyword enum voranstellen. Für eine einfache enum-Deklaration ist nur eine Liste von Namen erforderlich. Sie können aber auch ein oder mehrere mit jedem Namen verknüpfte Felder definieren.

  1. In Decoration.kt können Sie ein Beispiel für eine Aufzählung ausprobieren.
enum class Color(val rgb: Int) {
   RED(0xFF0000), GREEN(0x00FF00), BLUE(0x0000FF);
}

Aufzählungen sind ein wenig wie Singletons – es kann nur eine und nur jeweils einen Wert in der Aufzählung geben. Es kann beispielsweise nur ein Color.RED-, ein Color.GREEN- und ein Color.BLUE-Element geben. In diesem Beispiel werden die RGB-Werte der rgb-Property zugewiesen, um die Farbkomponenten darzustellen. Du kannst auch den Ordinalwert einer Aufzählung in der ordinal-Property und deren Namen in der name-Property abrufen.

  1. Versuchen Sie es mit einem anderen Beispiel einer Aufzählung.
enum class Direction(val degrees: Int) {
    NORTH(0), SOUTH(180), EAST(90), WEST(270)
}

fun main() {
    println(Direction.EAST.name)
    println(Direction.EAST.ordinal)
    println(Direction.EAST.degrees)
}
⇒ EAST
2
90

Schritt 3: Versiegelte Kurse erstellen

Eine versiegelte Klasse ist eine Klasse, die abgeleitet werden kann, aber nur innerhalb der Datei, in der sie deklariert wird. Wenn Sie versuchen, die Klasse in einer anderen Datei zu unterteilen, erhalten Sie eine Fehlermeldung.

Da sich die Klassen und Unterklassen in derselben Datei befinden, kennt Kotlin alle Unterklassen statisch. Bei der Kompilierung erkennt der Compiler also alle Klassen und abgeleiteten Klassen und weiß, dass dies alle sind. Deshalb kann er zusätzliche Prüfungen durchführen.

  1. Testen Sie in AquariumFish.kt ein Beispiel für eine versiegelte Unterrichtsklasse, die mit dem Wasserthema zusammenhängt.
sealed class Seal
class SeaLion : Seal()
class Walrus : Seal()

fun matchSeal(seal: Seal): String {
   return when(seal) {
       is Walrus -> "walrus"
       is SeaLion -> "sea lion"
   }
}

Die Seal-Klasse kann in einer anderen Datei nicht abgeleitet werden. Wenn Sie weitere Seal-Typen hinzufügen möchten, müssen Sie dies in derselben Datei tun. So sind geschützte Klassen eine sichere Möglichkeit, um eine feste Anzahl bestimmter Typen darzustellen. Versiegelte Kurse eignen sich beispielsweise hervorragend, um Erfolge oder Fehler von einer Netzwerk-API zurückzugeben.

In dieser Lektion wurden viele Themen behandelt. Auch wenn viele der Tools von anderen objektorientierten Programmiersprachen vertraut sein sollten, werden von Kotlin einige Funktionen hinzugefügt, die den Code kurz und verständlich halten.

Klassen und Konstruktoren

  • Definieren Sie eine Klasse in Kotlin mit class.
  • Kotlin erstellt automatisch Setter und Getter für Properties.
  • Definieren Sie den primären Konstruktor direkt in der Klassendefinition. Beispiel:
    class Aquarium(var length: Int = 100, var width: Int = 20, var height: Int = 40)
  • Wenn ein primärer Konstruktor weiteren Code benötigt, schreiben Sie ihn in einen oder mehrere init-Blöcke.
  • Mit constructor können in einer Klasse ein oder mehrere Konstruktoren definiert werden. Der Kotlin-Stil wird jedoch verwendet, stattdessen wird eine Factory-Funktion verwendet.

Sichtbarkeitsmodifikatoren und Unterklassen

  • Standardmäßig sind alle Klassen und Funktionen in Kotlin „public“. Sie können aber Modifikatoren verwenden, um die Sichtbarkeit in „internal“, „private“ oder „protected“ zu ändern.
  • Wenn Sie eine untergeordnete Klasse erstellen möchten, muss die übergeordnete Klasse als open gekennzeichnet sein.
  • Wenn Sie Methoden und Eigenschaften in einer Unterklasse überschreiben möchten, müssen sie in der übergeordneten Klasse mit open gekennzeichnet sein.
  • Eine versiegelte Klasse kann nur in der Datei abgeleitet werden, in der sie definiert wurde. Versiegeln Sie eine versiegelte Klasse, indem Sie der Deklaration das Präfix sealed voranstellen.

Datenklassen, Singleton-Werte und Aufzählungen

  • Erstellen Sie eine Datenklasse, indem Sie der Deklaration das Präfix data voranstellen.
  • Zerstörende ist eine Verknüpfung zum Zuweisen der Eigenschaften eines data-Objekts zu separaten Variablen.
  • Erstellen Sie eine Singleton-Klasse mithilfe von object statt class.
  • Erstelle eine Aufzählung mit enum class.

Abstrakte Klassen, Schnittstellen und Delegierung

  • Abstrakte Klassen und Schnittstellen sind zwei Möglichkeiten, um das Verhalten zwischen Klassen gemeinsam zu nutzen.
  • Eine abstrakte Klasse definiert Eigenschaften und Verhalten, aber die Implementierung bleibt Unterklassen vorbehalten.
  • Eine Schnittstelle definiert das Verhalten und kann Standardimplementierungen für einen Teil oder das gesamte Verhalten bereitstellen.
  • Wenn Sie Schnittstellen verwenden, um eine Klasse zu erstellen, wird die Funktionalität der Klasse durch die enthaltenen Klasseninstanzen erweitert.
  • Bei der Delegierung der Schnittstelle wird die Zusammensetzung verwendet, aber auch die Implementierung wird an die Klassenklassen delegiert.
  • Die Komposition ist eine leistungsstarke Möglichkeit, um mithilfe der Schnittstellendelegierung Funktionen zu einer Klasse hinzuzufügen. Im Allgemeinen ist es vorzuziehen, eine Komposition von einer abstrakten Klasse zu übernehmen, aber einige Probleme sind in diesem Fall besser geeignet.

Kotlin-Dokumentation

Wenn Sie weitere Informationen zu einem Thema in diesem Kurs benötigen oder nicht mehr weiterkommen, ist https://kotlinlang.org der beste Ausgangspunkt.

Kotlin-Anleitungen

Auf der Website https://try.kotlinlang.org finden Sie umfassende Anleitungen mit dem Namen Kotlin Koans, einem webbasierten Interpreter und eine umfassende Referenz mit Beispielen.

Udacity-Kurs

Informationen zum Udacity-Kurs zu diesem Thema finden Sie im Kotlin-Bootcamp für Programmierer.

IntelliJ IDEA

Die Dokumentation für IntelliJ IDEA finden Sie auf der JetBrains-Website.

In diesem Abschnitt werden mögliche Hausaufgaben für Schüler oder Studenten aufgeführt, die an diesem von einem Kursleiter geleiteten Codelab arbeiten. Die Lehrkraft kann Folgendes tun:

  • Bei Bedarf können Sie die entsprechenden Aufgaben zuweisen.
  • Schülern mitteilen, wie sie Aufgaben für die Aufgabe abgeben
  • Benoten Sie die Hausaufgaben.

Lehrkräfte können diese Vorschläge so oft oder so oft verwenden, wie sie möchten. anderen Aufgaben können sie nach Belieben zugewiesen werden.

Wenn Sie alleine an diesem Codelab arbeiten, können Sie Ihr Wissen mit diesen Hausaufgaben testen.

Diese Fragen beantworten

Frage 1

Klassen haben eine besondere Methode, die als Entwurf zum Erstellen von Objekten dieser Klasse dient. Wie wird die Methode genannt?

▢ Ein Builder

▢ Nutzer

▢ Ein Konstruktor

▢ Entwurf

Frage 2

Welche der folgenden Aussagen zu Schnittstellen und abstrakten Klassen ist NICHT richtig?

▢ Abstrakte Klassen können Konstruktoren haben.

▢ Schnittstellen können keine Konstruktoren haben.

▢ Schnittstellen und abstrakte Klassen können direkt instanziiert werden.

▢ Abstrakte Eigenschaften müssen von Unterklassen der abstrakten Klasse implementiert werden.

Frage 3

Welche der folgenden Optionen ist KEIN Kotlin-Sichtbarkeitsmodifikator für Eigenschaften, Methoden usw.?

internal

nosubclass

protected

private

Frage 4

Ziehen Sie diese Datenklasse in Betracht:
data class Fish(val name: String, val species:String, val colors:String)
Welcher der folgenden Werte ist NICHT gültig, um ein Fish-Objekt zu erstellen und zu destrukturieren?

val (name1, species1, colors1) = Fish("Pat", "Plecostomus", "gold")

val (name2, _, colors2) = Fish("Bitey", "shark", "gray")

val (name3, species3, _) = Fish("Amy", "angelfish", "blue and black stripes")

val (name4, species4, colors4) = Fish("Harry", "halibut")

Frage 5

Angenommen, Sie haben einen Zoo mit vielen Tieren, die sich um alles kümmern müssen. Welche der folgenden Maßnahmen zählt NICHT zur Implementierung der Pflegemaßnahmen?

▢: interface für verschiedene Arten von Lebensmitteln, die Tiere essen.

▢ Eine abstract Caretaker-Klasse, aus der Sie verschiedene Arten von Pflegekräften erstellen können.

interface zur Reinigung von sauberem Wasser.

▢: eine data-Klasse für einen Eintrag in einem Feedfeed

Fahren Sie mit der nächsten Lektion fort: 5.1-Erweiterungen.

Eine Übersicht über den Kurs, einschließlich Links zu anderen Codelabs, findest du im "Kotlin Bootcamp für Programmierer: Kurs.