Methoden (Prozeduren)
Unterprogramme und Funktionen
Programme werden schnell sehr groß
- unübersichtlich
- Wiederholung identischer oder ähnlicher Algorithmen
- sortieren einer Liste
- suchen eines Elements
Lösung
- Programm wird in kleinere Einheiten zerlegt (Unterprogramme)
- Unterprogramme werden aufgerufen
- Unterprogramme können sich gegenseitig aufrufen
Funktionen und Prozeduren (in Java: Methoden) sind in der Programmierung unverzichtbar, weil sie helfen, Code zu strukturieren, zu organisieren und wiederverwendbar zu machen. Ohne sie müsste man alle Anweisungen immer wieder neu schreiben, das würde Programme schnell unübersichtlich, fehleranfällig und schwer wartbar machen.
Durch Funktionen kann man bestimmte Aufgaben in klar abgegrenzte Abschnitte auslagern. So lässt sich zum Beispiel eine Berechnung, die an mehreren Stellen im Programm gebraucht wird, einmal sauber definieren und überall wiederverwenden. Das spart nicht nur Code, sondern stellt auch sicher, dass sich das Verhalten bei Änderungen konsistent anpasst.
Zudem machen Funktionen den Code lesbarer: Wenn man einem Funktionsnamen wie berechneSteuer() begegnet, versteht man sofort, was dort passiert, ohne sich durch viele Zeilen Code wühlen zu müssen oder die eventuell vorhandenen Kommentare zu lesen. Funktionen ermöglichen außerdem eine bessere Fehlersuche, weil man kleinere, isolierte Einheiten leichter testen und nachvollziehen kann.
In Java nennt man ein Unterprogramm grundsätzlich Methode (method)
Weitere Begriffe (außerhalb von Java)
- Funktion (function) gibt einen Wert zurück
- Prozedur (procedure) gibt nichts zurück
Methodendeklaration
- Methodendeklaration führt eine neue Methode ein
- Über Parameter können der Methode Daten übergeben werden
- Methode kann beliebig viele Parameter haben
- spezieller Rückgabetyp
voidfür Methoden, die nichts zurückliefern
static Rückgabetyp Name (Parameter) { Anweisungen }
static void printSum(int a, int b) {
int sum = a + b;
System.out.println(sum);
}
Arten von Methoden
- Methoden ohne Rückgabe und ohne Parameter
static void ohneAlles() { ... } - Methoden ohne Rückgabe und mit Parameter
static void mitParameter(int a) { ... } - Methode mit Rückgabe und ohne Parameter
static int mitRueckgabe() { ... } - Methode mit Rückgabe und mit Parameter
static int mitBeidem(int a, int b) { ... }
Signatur
In der Java-Programmierung bezeichnet man als Signatur einer Methode die wesentlichen Merkmale, durch die sich Methoden voneinander unterscheiden. Die Signatur ist insbesondere wichtig für das sogenannte Method Overloading, also das Definieren mehrerer Methoden mit demselben Namen, aber unterschiedlichen Parametern.
- Der Compiler erkennt Methoden anhand ihrer Signatur (type signature)
- Signatur besteht aus
- Name der Methode
- Typen und Anzahl der Parameter einer Methode (nicht den Namen der Parameter)
- Rückgabetyp ist nicht Teil der Signatur
- Beispiele
int max(int a, int b)→ Signatur:max(int, int)int max(int x, int y)→ Signatur:max(int, int)void max(int a, int b)→ Signatur:max(int, int)float min(float a, float b)→ Signatur:min(float, float)
Return-Anweisung
Mit dem Return-Anweisung (return statement) wird ein Wert von der Methode zurückgegeben
- Syntax:
return AUSDRUCK; - Typ des Ausdrucks muss zum Rückgabetyp der Methode passen
returnbeendet die Methode, nachfolgende Anweisungen werden nicht ausgeführt
static int addiere(int a, int b) {
int summe = a + b;
return summe;
}
static int addiere(int a, int b) {
return a + b;
}
static double mittelwert(double a, double b, double c, double d) {
return (a + b + c + d) / 4.0;
}
Methode mit Rückgabetyp void
- wird beendet, wenn Ablauf am Ende der Methode angekommen ist
- kann durch ein
returnauch an anderer Stelle beendet werden
Methode mit anderem Rückgabetyp
- muss mit
returneinen Wert zurückgeben - Compiler überprüft, ob auf allen möglichen Wegen ein
returnerfolgt
Mehrere return in einer Methode können für Anfänger verwirrend sein, gilt daher oft als schlechter Programmierstil: single entry, single exit
static void printMax(int a, int b) { // ohne return
if (a > b) {
System.out.println(a);
}
else {
System.out.println(b);
}
}
static void printMax(int a, int b) { // mit return
if (a > b) {
System.out.println(a);
return;
}
System.out.println(b);
}
Mehrere return-Anweisungen
static int max(int a, int b) {
if (a > b) {
return a;
}
else {
return b;
}
}
Nur eine return-Anweisung
static int max(int a, int b) {
int ergebnis;
if (a > b) {
ergebnis = a;
}
else {
ergebnis = b;
}
return ergebnis;
}
Methodenaufruf
Methoden können über ihren Namen aufgerufen werden
Syntax: METHODENNAME(PARAMETER);
- Formalparameter Parameter bei der Deklaration (Variablen)
- Aktualparameter aktueller Wert beim Aufruf (Wert)
- Anzahl entspricht Formalparametern
- Typ ist kompatible mit Formalparametern
Der Unterschied zwischen Aktualparametern und Formalparametern liegt im Zeitpunkt und Ort ihrer Verwendung: Formalparameter sind die Platzhalter in der Methodendefinition. Sie geben an, welche Werte eine Methode erwartet, und wie diese Werte innerhalb der Methode heißen. Man kann sie sich wie leere Variablen vorstellen, die erst bei einem Aufruf mit konkreten Werten gefüllt werden. Sie gehören zum „Bauplan“ der Methode. Aktualparameter (auch Argumente genannt) sind die konkreten Werte oder Variablen, die beim Aufruf einer Methode übergeben werden. Sie füllen die Formalparameter mit Leben und bestimmen, mit welchen Daten die Methode tatsächlich arbeitet.
static double mittelwert(double a, double b, double c, double d) {
return (a + b + c + d) / 4.0;
}
public static void main(String[] args) {
double durchschnitt = mittelwert(1.0, 2.7, 1.3, 4.0);
System.out.println(durchschnitt); // -> 2.25
}
- Formalparameter:
a,b,c,d - Aktualparameter:
1.0,2.7,1.3,4.0
Pass-by-Value beim Methodenaufruf
In Java bedeutet pass-by-value, dass beim Aufruf einer Methode nur der Wert der übergebenen Variable an die Methode übergeben wird, nicht die Variable selbst.
Bei Primitivtypen (z. B. int, double) wird der konkrete Wert übergeben. Änderungen innerhalb der Methode wirken sich nicht auf die ursprüngliche Variable außerhalb der Methode aus. Auch bei Objekten arbeitet Java mit pass-by-value; der übergebene Wert ist in diesem Fall die Referenz auf das Objekt.
Übergabe von Daten an Methode erfolgt per Wertübergabe (pass by value) (im Gegensatz zu Referenzübergabe (pass by reference))
- Wert des Aktualparameters wird kopiert
- Methode arbeitet auf einer Kopie
- Wert beim Aufrufer bleibt unverändert
Dies gilt auch für Referenzvariablen
static void methode(int a) {
a++; // schlechter Stil (s.u.)
System.out.println("a = " + a);
}
public static void main(String[] args) {
int b = 17;
methode(b);
System.out.println("b = " + b);
}
a = 18
b = 17
Das gezeigte Java-Programm demonstriert das Konzept von pass-by-value anhand eines primitiven Datentyps (int):
Ablauf:
- In
main()wird eine Variablebmit dem Wert17deklariert. bwird an die Methodemethode(int a)übergeben.- Java übergibt dabei den Wert von
b, also17, nicht die Variable selbst. - In der Methode wird die Kopie von
aum eins erhöht (a++→a = 18). awird ausgegeben: „a = 18“- Zurück in
main()bleibtbunverändert: „b = 17“
static void methode(int[] a) {
a[0]++;
}
public static void main(String[] args) {
int[] b = { 1, 2, 3 };
System.out.println("b[0] = " + b); // vor Aufruf
methode(b);
System.out.println("b[0] = " + b); // nach Aufruf
}
b[0] = 1
b[0] = 2
In diesem Java-Programm ändert sich der Wert von b[0] nach dem Methodenaufruf, obwohl Java immer pass-by-value verwendet. Das liegt daran, was übergeben wird: hier eine Referenz auf ein Array.
- In
main()wird ein Arraybmit den Werten{1, 2, 3}erstellt. bwird an die Methodemethode(int[] a)übergeben.- Java übergibt eine Kopie der Referenz auf das Array (pass-by-value der Referenz).
- In der Methode
methodezeigtaauf dasselbe Array wieb, beide Referenzen verweisen auf dasselbe Objekt im Speicher. a[0]++erhöht den Wert am Index 0 direkt im Array.- Dadurch ändert sich auch der Wert, den
b[0]inmain()sieht.
Dokumentation von Methoden
JavaDoc-Kommentare dienen dazu, automatisch dokumentierten Quellcode zu erstellen. Sie sind speziell formatierte Kommentare in Java, die direkt über Klassen, Methoden oder Attributen stehen und vom JavaDoc-Werkzeug zu einer lesbaren HTML-Dokumentation verarbeitet werden können.
Methoden werden mit JavaDoc dokumentiert (→ Pflichtübungen)
- Spezieller Kommentar mit
/** */ - Parameter werden über
@paramerläutert - Rückgabewert wird mit
@returnbeschrieben
/**
* Summiert zwei Zahlen.
*
* @param a erste Zahl
* @param b zweite Zahl
* @return Summe der zwei Zahlen
*/
static int sum(int a, int b) {
return a + b;
}
Zweck von JavaDoc-Kommentarren
- Dokumentation für Entwickler:innen: JavaDoc-Kommentare erklären, was eine Klasse, Methode oder ein Attribut tut, welche Parameter verwendet werden und was zurückgegeben wird.
- Lesbarkeit und Wartbarkeit: Gut dokumentierter Code ist leichter zu verstehen, besonders für andere Entwickler:innen oder beim späteren Überarbeiten.
- Automatische Dokumentation: Mit dem Tool
javadocwird aus dem Quellcode eine strukturierte Online-Dokumentation erstellt, ähnlich wie die offizielle Java-API. Diese kann zusammen mit den eigenen Klassen weiter gegeben werden.
JavaDoc-Kommentare beginnen mit /** und enden mit */. Darin verwendet man spezielle Tags wie:
@param– beschreibt einen Parameter@return– erklärt den Rückgabewert@throws– beschreibt geworfene Ausnahmen
Überladene Methoden
Überladene Methoden sind nützlich, weil sie es ermöglichen, mehrere Methoden mit demselben Namen, aber unterschiedlicher Parameterliste zu definieren. Dadurch könnenunterschiedliche Varianten einer Funktionalität unter dem gleichen Methodennamen zusammengefasst werden.
Überladene Methode (overloaded method)
- In Java dürfen mehrere Methoden denselben Namen haben, solange sich die Parameter unterscheiden
- in der Anzahl
- in dem Typ
- in Anzahl und Typ
- müssen unterschiedliche Signaturen haben
- Compiler wählt beim Aufruf die Methode mit den richtigen Parametern aus
Warum sind überladene Methoden nützlich?
- Verbesserte Lesbarkeit und Einheitlichkeit: Methoden, die ähnliche Aufgaben erledigen, können denselben Namen tragen. Beispiel:
drucke(String text),drucke(int zahl), gleiche Aufgabe: etwas ausgeben, aber unterschiedliche Datentypen. - Flexibilität für den Programmierer:innen: Die Benutzer:innen einer Methode müssen sich nur einen Namen merken, egal welchen Datentyp sie übergeben möchten. Java entscheidet automatisch anhand der Parameter, welche Variante aufgerufen wird.
- Kein doppelter Code nötig: Man kann elegant Varianten von Methoden haben, die aufeinander aufbauen.
static int max(int a, int b) { // Variante 1
return a > b ? a : b;
}
static int max(int a, int b, int c) { // Variante 2
return max(a, max(b, c));
}
static double max(double a, double b) { // Variante 3
return a > b ? a : b;
}
static double max(double a, double b, double c) { // Variante 4
return max(a, max(b, c));
}
public static void main(String[] args) {
System.out.println(max(1, 2)); // Aufruf Variante 1
System.out.println(max(3, 2, 5)); // Aufruf Variante 2
System.out.println(max(1.0, 2.0)); // Aufruf Variante 3
System.out.println(max(3.0, 2.0, 5.0)); // Aufruf Variante 4
}
Vararg-Methoden
Vararg-Methoden (Kurzform für „variable arguments“) in Java ermöglichen es, einer Methode eine beliebige Anzahl von Argumenten desselben Typs zu übergeben, ohne vorher ein Array erzeugen zu müssen.
Java erlaubt Methoden mit beliebiger Anzahl von Parametern: Varag-Methoden
- Methode kann beliebig viele normale Parameter haben (0–n)
- letzter Parameter kann Vararg-Parameter sein (symbolisiert durch Ellipse)
- Syntax:
TYP... name - Parameter stehen als Array vom gegebenen Typ zur Verfügung
static int max(int... werte) { /* ... */ }
static int summe(int a, int b, int... summanden) { /* ... */ }
static void print(String text, double... zahlen) { /* ... */ }
Zweck von Vararg-Methoden:
- Flexibilität: Eine Methode kann mit unterschiedlich vielen Parametern aufgerufen werden.
- Benutzerfreundlichkeit: Man kann mehrere Werte direkt übergeben, ohne sie zuerst in ein Array zu packen.
- Einheitliche Schnittstelle: Eine Methode kann verschiedene Aufrufe elegant verarbeiten, ob mit einem, mehreren oder keinem Argument.
static int max(int... werte) {
int ergebnis = 0;
for (int wert : werte) {
ergebnis = wert > ergebnis ? wert : ergebnis;
}
return ergebnis;
}
public static void main(String[] args) {
int maximum = max(190, 230, 155, 891, 452);
System.out.println(maximum); // -> 891
System.out.println(max(190)); // -> 190
System.out.println(max()); // -> 0
}
Lokale Variablen
Lokale Variablen in Java sind Variablen, die innerhalb einer Methode, eines Konstruktors oder eines Blocks deklariert werden und nur innerhalb dieses Bereichs (Scopes) gültig sind.
Methoden können eigene Variablen haben, die lokalen Variablen (local variable)
- alle im Methodenrumpf deklarierten Variablen sind lokal
- alle Parameter verhalten sich wie lokale Variablen
- sind nur im Rumpf der Methode sichtbar
- gehen nach Beenden der Methode verloren
- Wert kann über
returnan Aufrufer zurückgegeben werden
Variablen der aufrufenden Methode
- in der aufgerufenen Methode nicht sichtbar
- Wertübergabe an aufgerufene Methode über Parameter
Eigenschaften lokaler Variablen:
- Sichtbarkeit (Scope)
- Sie sind nur innerhalb des Blocks sichtbar, in dem sie deklariert wurden.
- Außerhalb dieses Blocks kann man nicht auf sie zugreifen.
- Lebensdauer
- die Variable wird erst beim Eintritt in den Block erstellt und beim Verlassen wieder zerstört.
- Es gibt keine automatische Initialisierung, man muss sie explizit initialisieren, bevor man sie verwendet.
- Speicherort
- Lokale Variablen werden auf dem Stack (siehe unten) gespeichert.
- Stack wird beim Verlassen der Methode gelöscht.
Zweck lokaler Variablen:
- Temporäre Daten speichern, die nur innerhalb einer Methode benötigt werden.
- Rechenwerte zwischenspeichern, z. B. Zwischenergebnisse in Schleifen oder Bedingungen.
- Speicherplatz sparen, da sie nach der Verwendung automatisch gelöscht werden.
- Kapselung und Übersichtlichkeit erhöhen, indem man Variablen nur dort definiert, wo sie gebraucht werden.
static int sum(int a, int b) {
// Variablen x, y und summe nicht sichtbar
int ergebnis; // lokale Variable
ergebnis = a + b;
return ergebnis; // Rückgabe des Wertes der Variable
}
public static void main(String[] args) {
int x = 5; // lokale Variable
int y = 10; // lokale Variable
int summe; // lokale Variable
summe = sum(x, y);
System.out.println(summe); // -> 15
}
Sichtbarkeit (visibility): Variablen sind nur an bestimmten Stellen sichtbar
- _Lokale Variablen im Rumpf der Methode
sichtbar von Deklaration bis Methodenende - Lokale Variablen in einem Block
sichtbar von Deklaration bis Ende des Blocks - Variable im Initialisierungsteil einer for-Schleife
sichtbar im Rumpf der Schleife - Parameter einer Methode
sichtbar von Deklaration bis Methodenende
static int maximum(int[] werte) {
int laenge = werte.length;
int max = 0;
for (int i = 0; i < laenge; i++) {
if (werte[i] > max) {
max = werte[i];
}
}
return max;
}
public static void main(String[] args) {
int[] werte = { 8, 17, 5, 42, 3, 41, 8 };
System.out.println(maximum(werte)); // -> 42
}
Parameter als lokale Variablen
- Methodenparameter verhalten sich wie lokale Variablen
- Zuweisung an Parameter ist möglich aber schlechter Stil
// Pfui!
static int max(int a, int b) {
a = a > b ? a : b;
return a;
}
// Richtig
static int max(int a, int b) {
int ergebnis = a > b ? a : b;
return ergebnis;
}
Globale Variablen
Globale Variablen (global variables) werden außerhalb von Methoden deklariert und sind in allen Methoden sichtbar
- Syntax:
static Datentyp name; - sollten vermieden werden, da Programme mit ihnen schwerer zu verstehen sind
class Global {
static int zaehler;
static void methode() {
zaehler++;
}
public static void main(String[] args) {
methode();
methode();
System.out.println(zaehler); // -> 2
}
}
Seiteneffekt
Seiteneffekt (side effect) bezeichnet die Veränderung von globalem Zustand aus einer Methode
- Nachteile
- in Signatur der Methode nicht erkennbar
- erschwert Fehlersuche
- schränkt Wiederverwendbarkeit ein
- schlechter Programmierstil
- guter Programmierstil
- keine globalen Variablen verwenden
- Werteübergabe an Methode ausschließlich per Parameter
- Ergebnis über Rückgabewert zurückgeben
Datenstrukturen Stack und Heap
Zwei grundlegende Arten von Speicher
- Stack
- auch genannt Kellerspeicher
- auch genannt Stapelspeicher
- auch genannt LIFO-Speicher (last in first out)
- nimmt nur lokale Variablen auf
- Heap zu Deutsch Haufen und Halde
- wird vom Garbage Collector aufgeräumt (s. u.)
- nimmt nur Objekte auf
Ein Stack ist eine Datenstruktur, die nach dem Prinzip „Last In, First Out“ (LIFO) funktioniert. Das bedeutet, dass das Element, das zuletzt hinzugefügt wurde, auch als Erstes wieder entfernt wird.
Man kann sich den Stack als einen Stapel von Büchern vorstellen: Wenn man ein neues Buch auf den Stapel legt, liegt es ganz oben. Wenn man ein Buch nehmen will, muss man zuerst das oberste entfernen, bevor man an die darunterliegenden kommt.
- Zugriff nur auf das oberste Element
- Last in First Out
Ein Stack unterstützt typischerweise zwei Hauptoperationen: Mit push wird ein Element oben auf den Stack gelegt, und mit pop wird das oberste Element entfernt und zurückgegeben. Oft gibt es auch eine peek-Funktion, die das oberste Element anschaut, ohne es zu entfernen.
Im Speichermanagement bezeichnet „Heap“ einen Bereich des Arbeitsspeichers, der zur dynamischen Speicherverwaltung verwendet wird. Er unterscheidet sich vom Stack, der für lokale Variablen und Funktionsaufrufe zuständig ist.
Wenn ein Programm während der Laufzeit Objekte oder Datenstrukturen erstellen möchte, deren Größe oder Lebensdauer nicht im Voraus bekannt ist, nutzt es den Heap. In Java geschieht das zum Beispiel mit dem Schlüsselwort new. Jedes Objekt, das so erzeugt wird, landet im Heap.
Wahlfreier Zugriff auf die Elemente
Einsatz des Stacks
Methoden
- können Methoden rufen
- haben lokale Variablen, die bis zum Ende leben
- haben lokale Variabeln, die nach dem Ende der Methode zerstört werden müssen
- übergeben Parameter an andere Methoden
- geben Werte zurück (
return)
Wie verwaltet man den Speicher für Variablen, Parameter und Rückgabewerte?
Aufruf einer Methode
- Aktivierungssatz (stack frame) wird auf dem Stack erzeugt, enthält
- Parameter
- lokale Variablen
- Platz für interne Rechenoperationen der Methode
Rückkehr der Methode
- Rückgabewert wird auf den Stack des Aufrufers geschrieben
- Aktivierungssatz der Methode wird vom Stack entfernt
- Speicher von lokale Variablen werden gelöscht
- Speicher für Parameter wird freigegeben
Da es sich bei der Java-VM nicht um eine Register-, sondern eine Stack-Maschine handelt, werden alle Rechenoperationen des Java-Programms auf einem sogenannten Operanden-Stack (operand stack) durchgeführt. Dieser wird ebenfalls im Aktivierungssatz abgelegt. Die Größe des Operanden-Stacks hängt von den Operationen ab, die in der Methode durchgeführt werden und wird vom Compiler berechnet. Entsprechend viel Platz wird im Aktivierungssatz für den Operanden-Stack reserviert. Zusätzlich berechnet der Compiler den benötigten Platz für die lokalen Variablen und Parameter und reserviert diesen ebenfalls für den Aktivierungssatz. (Vgl. Java-VM Spezifikation, Kapitel 2.6)
Die Rückgabe eines Wertes von einer Methode an den Aufrufer erfolgt, indem der Rückgabewert auf den Operanden-Stack der aufrufenden Methode geschrieben wird. Hierzu dienen spezielle Byte-Code-Instruktionen (z. B. areturn). (Vgl. Java-VM Spezifikation, Kapitel 6.5)
static long sum(int a, int b) {
long ergebnis = a + b;
return ergebnis;
}
public static void main(String[] args) {
long ergebnis = sum(2, 9);
System.out.println(ergebnis); // -> 11
}
Vor dem Aufruf der sum-Methode liegt nur die main-Methode auf dem Stack (linkes Bild). Danach wird die sum-Methode aufgerufen und ein entsprechender Aktivierungssatz wird auf dem Stack erzeugt (mittleres Bild). Sobald die Methode zurückkehrt, wird das Ergebnis an die main-Methode zurückgegeben und der Aktivierungssatz der sum-Methode wird gelöscht.
Um die Darstellung in der Abbildung nicht zu kompliziert zu gestalten, wurde der Operanden-Stack nicht dargestellt.
Stack und Heap
Auf dem Stack können in Java nur abgelegt werden
- Variablen primitiver Datentypen
- Referenzvariablen
Alle anderen Datentypen liegen auf dem Heap
- Strings
- Arrays
- Objekte
Objekt
- liegt immer auf dem Heap
- trägt Daten (primitive Datentypen oder Referenzen)
Referenz (reference) (Referenzvariable)
- ist kein Objekt
- zeigt auf ein Objekt
- kann auf dem Heap liegen (Variable in einem Objekt)
- kann auf dem Stack liegen (lokale Variable)
- kann zu verschiedenen Zeiten auf verschiedene Objekte zeigen
Objekt vs. Referenz
Ein Objekt ist eine Instanz einer Klasse, die Daten und Methoden enthält. Eine Referenz ist eine Variable, die auf ein bestimmtes Objekt verweist. Ein Objekt selbst kann in den Arbeitsspeicher (Heap) geladen werden, während eine Referenz lediglich einen Verweis auf das Objekt enthält. Das bedeutet, dass mehrere Referenzen auf das gleiche Objekt verweisen können.
- Objekt (object)
- liegt immer auf dem Heap
- trägt Daten (primitive Datentypen oder Referenzen)
- Referenz (reference)
- ist kein Objekt
- zeigt auf ein Objekt
- kann auf dem Heap liegen (als Variable in einem Objekt)
- kann auf dem Stack liegen (als lokale Variable)
- kann zu verschiedenen Zeiten auf verschiedene Objekte zeigen
int k = 32;
int l = k;
String greeting = new String("Hallo");
String gruezi = greeting;
Garbage Collection
Garbage Collection (auf Deutsch: Speicherbereinigung) ist ein automatischer Prozess in Programmiersprachen wie Java, der dafür sorgt, dass nicht mehr benötigter Speicherplatz auf dem Heap freigegeben wird.
In Java wird Speicher für Objekte mit dem Schlüsselwort new dynamisch im Heap reserviert. Solange ein Objekt noch über mindestens eine Variable oder Referenz erreichbar ist, bleibt es im Speicher erhalten. Wenn jedoch kein Teil des Programms mehr auf ein Objekt zugreift, gilt es als nicht mehr erreichbar, es wird also vom Programm nicht mehr verwendet. Genau hier kommt die Garbage Collection ins Spiel.
Die Garbage Collection erkennt solche nicht mehr erreichbaren Objekte und entfernt sie automatisch aus dem Speicher. Dadurch wird verhindert, dass sich der Speicher mit ungenutzten Objekten füllt, was langfristig zu einem Speicherüberlauf (OutOfMemoryError) führen könnte.
- Stack sorgt für Abräumen der lokalen Variablen
- Heap wird vom Garbage Collector aufgeräumt
- durchläuft den Heap und sucht Objekte, die nicht mehr referenziert werden
- entfernt alle unbenutzten Objekte
Ein Vorteil der Garbage Collection ist, dass sich Entwickler:innen nicht selbst um das manuelle Freigeben von Speicher kümmern müssen, wie es etwa in C oder C++ notwendig ist. Das verringert die Gefahr von Speicherlecks oder Zugriffsfehlern auf bereits freigegebene Speicherbereiche.
Die Garbage Collection läuft im Hintergrund und entscheidet selbstständig, wann sie aktiv wird. Dabei achtet sie auf Effizienz, kann aber unter Umständen zu kurzen Verzögerungen im Programmablauf führen, wenn größere Speicherbereiche untersucht werden müssen.