Speicherverwaltung in JVM-Sprachen
Bevor wir uns genauer mit dem Lebenszyklus von Objekten auseinander setzen, wollen wir erst verstehen, wie denn zur Laufzeit des Programms (innerhalb der JVM) Objekte (oder Werte) gespeichert werden.
Grundsätzlich werden alle Objekte (in Kotlin ist alles ein Objekt) zur Laufzeit im Hauptspeicher des Computers abgelegt. Ein Enten-Objekt, welches wir auf diese Weise erzeugen:
class Ente()
fun main(){
val donald = Ente() // Mit Ente() rufen wir den Konstruktor der Klasse auf und erhalten ein Ente-Objekt
}
wird also im RAM abgelegt. Allerdings sind die Feinheiten etwas komplizierter, als "Speichere das Objekt irgendwo im freien Hauptspeicher".
Für die Objektverwaltung existieren zwei separate Bereiche im Hauptspeicher: der Heap und der Stack
Heap und Stack
Wer erleben möchte, wie der Heap überfüllt wird und die JVM mit einem Out-Of-Memory-Error crasht, kann sich den rechts verlinkten Code herunter laden und auf dem eigenen Rechner ausführen.
Anonyme Objekte
Was sollen denn anoyme Objekte sein? Man benennt deren Referenzvariable doch, wenn man sie erzeugt. Zum Beispiel:
Unsere Referenzvariable heißt donald
, hierbei handelt es sich nicht um ein anonymes Objekt. Aber ich kann diesen Code auch so formulieren:
Jetzt wird der Funktion braten()
keine Referenz übergeben, sondern direkt ein Objekt (durch den Aufruf des Konstruktors der Klasse Ente
). Aber dieses Objekt bekommt keine Referenzvariable. Es ist anonym.
Anonyme Objekte sind so etwas wie Wegwerfprodukte, die keine eigene Referenzvariable erhalten.
Genau genommen können wir hier noch weiter anonymisieren:
Null ist nicht 0
Wenn Objekt und Referenz zwei unterschiedliche Dinge sind, können diese dann auch getrennt voneinander existieren?
Bisher haben wir stets eine Referenz mit einem Objekt verknüpft, um Zugang zum Objekt über die Referenzvariable zu erhalten. Eine sinnvolle Antwort auf die oben gestellte Frage müsste aber (zumindest in JVM-Sprachen) Jein heißen.
Objekt ohne Referenz
Wie im Video erklärt wurde, ist dieser Fall relativ leicht zu beantworten. Die Garbage-Collection entsorgt Objekte, zu denen keine Referenz mehr existiert. Falls also ein Objekt nicht mehr zugänglich ist, wird es aus dem Heap entfernt.
Achtung: Objekte ohne Referenz sind nicht automatisch anonyme Objekte! (diese haben keine Referenzvariable)
Referenz ohne Objekt
Man kann auch Referenzvariablen erzeugen, um diese dann erst später mit einem Objekt zu verbinden. In klassischem Java ist das sehr üblich. Dort werden ständig Referenzvariablen deklariert, die erst später initialisiert werden. Problematisch wird das, wenn man das Initialiseren vergisst (oder es fehlschlägt) und die Referenzvariable ins Leere zeigt. Diese Leere nennt man null (gesprochen: [nʌl]. Dieses null ist übrigens nicht der Zahlentwert 0, sondern beschreibt die Abwesenheit eines Objekts hinter einer Referenz. Wenn man eine Referenzvariable aufruft, hinter der eine Referenz auf null zeigt, wirft das Programm eine sogenannte nullPointerException. In nicht wenigen Fällen crasht die Anwendung dann. Dies gilt es also zu verhindern.
Null in Kotlin
Da nullPointerExceptions zu den wohl häufigsten Fehlern gehören, die beim Programmieren auftreten, wurde bei der Entwicklung von Kotlin darauf geachtet, diese zu verhindern, bzw. diese vor die Kompilierung zu verlagern.
Alle Fehler, die vor der Kompilierung und nicht zur Laufzeit auftreten, sind gute Fehler.
Alle regulären Datentypen in Kotlin sind null-safe, das bedeutet, dass sie niemals null-Werte referenzieren können:
Gerne können Sie mit dem Datentyp in diesem Code-Snippet spielen und String oder Double eingeben. Der Compiler verbietet dies mit der Meldung:
In Kotlin müssen alle Objekte mit einem Wert initialisiert werden, es sei denn, man erlaubt explizit null-Werte. Dies wird in einem separaten Kapitel behandelt.
Ein Kommentar