Praktikumsaufgabe 1
Die Information ist eine Zusammenfassung der Kapiteln 14, 19 und 20 vom „Programmieren lernen mit
Kotlin, Grundlagen, Objektorientierung und fortgeschrittene Konzepte“, Christian Kohls, Alexander
Dobrynin, Florian Leonhard
1. Klassen
= eine Klasse beschreibt die allgemeine Struktur des Datentyps
= definiert einen neuen Datentyp
= beschreibt die allgemeine Struktur für Objekte dieser Kasse
a) Objekte
= spezifische Exemplare einer Klasse
= „Instanzen“ einer Klasse
= speichern konkrete Werte
c) Zugriff auf die einzelne Eigenschaften des Objekts erfolgt durch die Variable, die auf
dieses Objekt referenziert, und ein Punkt: variable.eigenschaft
d) Konstruktoren
a. damit kann man festlegen was beim Konstruieren des Objekts geschehen soll
b. Klasse (var eigenschaft1 : Typ, var eigenschaft2: Typ) ist ein Konstruktor. in
ihm können die Variablen var oder val sein, je nach Bedarf. Wir müssen
außerdem den Typ angeben
c. Definition = der Konstruktor erzeugt ein Objekt gemäß der Klassenstruktur,
Alle Eigenschaften werden mit Werten initialisiert.
d. Schlüsselwort constructor, aber kann weggelassen werden
e. Im Konstruktor können folgende Dinge festgelegt werden
i. var Eigenschaften
ii. val Eigenschaften
iii. Sichtbarkeitsmodifikatoren vor den Eigenschaften : private, internal
etc.
iv. weitere Parameter ohne val und var davor
f. Unterschied zu einfachen Funktionen: hier können Eigenschaften des Objekts
definiert werden
g. Eigenschaft = eine Variable, die zu einem Objekt gehört
e) Parameter im Konstruktor
a. kein Schlüsselwort var/val
b. verwendet, um die Eigenschaften zu initialisieren und sind im Rumpf der
Klasse und in dem init Block verfügbar.
f) Init Blöcke
a. ein Block zum Aufbereiten, Berechnen von Werten oder sonstigen Aktionen
beim Konstruieren eines Objekts
b. optional
c. beim Aufruf des Konstruktors aufgerufen
i) Sekundäre Konstruktoren
a. selten benutzt
b. für zusätzliche Berechnungen
c. Schlüsselwort constructor
d. Das Bauen des Objekts erfolgt weiterhin durch den primären Konstruktor
e. der sek. Konstruktor darf keine weiteren Eigenschaften einführen
f. der sek. Konstruktor definiert eine Parameterliste und benutzt diese, um die
eigentliche Konstruktion des Objektes an den primären Konstruktor zu
delegieren
g. Beispiel aus dem Buch:
class Glass (var content: Int, val capacity: Int){
constructor (part: Double, capacity: Int){
this. ((part*capacity).toInt(), capacity)
j) Default Arguments
a. wenn wir eine Eigenschaft immer gleich haben wollen, können wir einen
Default Wert im Konstruktor setzen und dieser Wert ist für alle Objekte dann
gleich. Wenn beim Erzeigen eines anderen Objektes ein anderer Wert
angegeben wird, dann hat dieser Objekt den Default Wert nicht mehr,
sondern den neuen Wert.
b. die Reihenfolge der übergebenen Werte ist relevant: es ist sinnvoll die Default
Arguments hinter alle anderen zu setzen
c. Dadurch sparen wir uns das Definieren weiterer Konstruktoren und
Funktionen
k) Named Arguments
a. wir teilen dem Compiler mit, welcher Parameter gerade übergeben wird
(wenn mehrere Default Parameter im Konstruktor vorhanden)
b. Reihenfolge dabei nicht relevant
c. Lesbarkeit ist besser
d. Beispiel: val glass1 = Glass (capacity = 50, content = 10)
3. Datenkapselung
a) um den Wert der Eigenschaft kontrollieren zu können
b) Setter Methoden
a. zB zu überprüfen, ob eine Eingabe im Konstruktor valide ist. Wenn nicht
können wir selbst bestimmen welchen Wert übernommen wird. Z.B. wenn -9
eingegeben wird, können wir festlegen, dass eine 0 gesetzt wird. Wenn 100
übergeben wird, können wir festlegen, dass der Wert der maximalen Inhalt
eines Glases gesetzt wird. ==== Wir korrigieren den Wert
b. Vorteil: wir können regeln, ob die Eigenschaft tatsächlich gesetzt wird und
wie sie gesetzt wird.
c. set Methode wird automatisch erzeugt und weist den übergebenen Wert dem
sogenannten Backing Field zu
d. Backing Field = das eigentliche Datenfeld vom Int Objekt. Speicherplatz, wo
der Wert steht. Schlüsselwort field
e. Schritte für set Methode:
i. Eigenschaft im Rumpf der Klasse legen
ii. set Methode definieren
iii. im Konstruktor ein Parameter festlegen
f. set(value) <- value kann beliebig benannt werden, aber das ist die Konvention
g. wir setzen den value immer in das Eigenschaftsfeld field
h. wir ändern die Klassenstruktur intern, aber dies ist nicht nach außen sichtbar
i. Der Wert sollte niemals auf die Eigenschaft selbst gesetzt werden, immer auf
field!!! sonst entsteht eine Endlosrekursion
j. wenn ein Wert im Klassenrumpf oder in der Parameterlist gesetzt wird, wird
dieser Wert direkt auf field gesetzt und set Methode wird übersprungen.
Deshalb ist ein init Block notwendig, um sicher zu sein, dass die set Methode
aufgerufen wird.
k. val Variablen haben keine set Methode
c) getter Methoden
a. Methode in <Eigenschaft umwandeln = berechnete Eigenschaft
b. für kurze Berechnungen
c. Beispiel:
val full: Boolean
get() = content == capacity
val fillLevel: Float
get() = content.toFloat()/capacity
d. get hat immer als Rückgabetyp den Typ der Variable !!!
d) set und get können auch für Eigenschaften bereitgestellt werden, ohne dass ein
Backing Field zum Speichern der Daten benötigt wird. Die Eigenschaft wird berechnet.
Nach außen ist das nicht sichtbar.
e) Backing Fields sind immer private und niemals direkt veränderbar.
b. für Value Objects muss die equals Methode überschrieben werden, damit sie
true liefert, wenn 2 Objekte mit denselben Werten verglichen werden.---->
aufwendig ---> Data Klassen
c. Schlüsselwort data
d. der Compiler generiert automatisch die Methoden zum Vergleichen
e. für data Klassen ist equals so definiert, dass sie true liefert, wenn zwei Objekte
mit denselben Eigenschaftswerten verglichen werden.
b) ENUM Klassen
a. =Enumeration = Aufzählung
b. Aufzählungsklassen
c. alle mögliche Werte eines bestimmten Wertebereichs werden vollständig
aufgezählt
d. zum Abbilden von ordinalen und nominalen Datentypen
e. ordinal = Daten mit einer Rangfolge. Abstände zwischen den Rangen ist
unbekannt. Z.B Wochentage, Schulnoten; Rang durch Ordnungszahl
angegeben, angefangen mit 0
f. nominal = kein Rang. z.B Laufrichtung bei Spielfiguren: hoch, rechts, links,
runter etc.
g. Schlüsselwort enum
h. Beispiel:
enum class WeekDay ( val title: String){
MONDAY(“Monday”)
TUESDAY(“Tuesday”)
…
}
i. Um eine Methode der enum Klasse hinzuzufügen, muss man am Ende der
Aufzählung Semikolon dazuschreiben und dann erst die Funktion.
j. Mit der Methode Klassenname.values() werden alle Enum Konstanten
abgefragt
k. Mit der Methode Klassenname.valueOf(value:String) wird eine Enum
Konstante zurückgegeben mit Namen = value.
6. Nullfähigkeit
a) Es gibt Fälle, in denen eine Referenzvariable auf kein Objekt verweisen soll
b) Schlüsselwort null
c) Syntax: Fragezeichen nach dem Typ der Refeferenzvariable: Typ?
var bestMovie : Movie? = null
d) Ein nullfähiger Typ kann entweder einen Wert haben oder nicht. Nullfägihe Typen
heißen auch noch Optionals , weil der Wert optional ist.
e) Kotlin verschiebt die Nullfähigkeit auf die Typebene
f) wenn nullfähige Typen gänzlich andere Typen sind, können wir keine Operationen wie
+ und – auf nullfähige Basis-Datentypen verwenden. Man muss die Nullfähigkeit
auflösen.
g) Vor jedem Zugriff müssen wir prüfen, ob ein Objekt existiert
a. Überprüfen mit if-Anweisung --> Smart Cast
if ( bestMovie!=null)
bestMovie.title
b. Safe Calls
i. Safe Call Operator ?.
bestMovie?.title
ii. wenn bestMovie null ist, dann ist der gesamte Ausdruck auch null
iii. verkettete Safe Calls :
bestMovie?.mainActor?.firstName
obwohl mainActor nicht nullfähig ist, müssen wir 2x Safe Call
anwenden. Wenn kein bestMovie existiert wird der ganze Ausdruck
null. Wir müssen sicherstellen, dass der Zugriff auf firstName nur
erfolgt, wenn die Auswertung des ersten Teilausdrucks nicht null ist
h) Nullfähigkeit auflösen
a. if else Block: Wenn der if-else Block einen Standardwert setzt:
val actorName : String =
if(bestMovie != null) bestMovie.mainActor.firstName
else “Niemand”
Das Entscheidende ist, dass wir actorName als String angeben und nicht
String?
b. Elvis Operator
i. versucht einen nullfähigen Ausdruck auszuwerten
ii. Ausdruck != null → Ausdruck verwendet
iii. Ausdruck == null → Standardwert genommen
iv. Elvis Operator ?:
val actorName : String = bestMovie?.mainActor?.firstName ?:
“Niemand”
v. die beiden Ausdrücke links und rechts haben den gleichen Typ
c. Erzwungenes Auflösen
i. lieber nicht benutzen !!
ii. Syntax : !! nach der Variable
7. Exceptions
a) sowohl ein Konzept als auch eine Klasse
b) beschreibt Ausnahmebehandlung
c) Findet Fehler im Programm
d) die Klasse Exception repräsentiert die Art von Fehlern
e) Beispiele: NullPointerException, NoSuchElementException etc.
f) Komponente
a. Nachricht von Typ String?, die Details der Exception enthält
b. Stack Trace vom Typ Array<StackTraceElement> : zeigt die Funktionsaufrufe,
die zur Exception geführt haben
c. Ursache der Exception vom Typ Throwable?
g) Beispiele
a. ArrayIndexOutOfBoundsException
i. wenn man mit ungültigem Index auf ein Array zugreifen will
ii. Wenn man die Exception nicht auffängt, werden alle Zeile nach dem
Fehler nicht ausgeführt -> der Code crasht
b. ArithmeticException
i. zB durch Division mit 0
j) Exceptions werfen
a. Schlüsselwort throw
b. Beispiel: throw Exception („Das ist eine Exception“) oder auch throw
ArithmeticException() oder throw IllegalArgumentException(„Division durch 0
ist unmöglich“)
k) Exceptions erzeugen
a. class ExceptionName : Exception()
b. von Exception abgeleitet
c. keine weitere Methoden oder Eigenschaften