Local Classes
Lokale Klassen
Lokale Klassen (local classes)
- Deklaration einer Klasse innerhalb einer Methode
- Name der Klasse ist nur innerhalb der Methode sichtbar
- Äußere Klasse kann nicht auf die lokale Klasse zugreifen
- Instanzen können nur innerhalb der Methode angelegt werden
class A {
void methode() {
class B { }
}
}
Wenn man Klassen in Methoden deklariert, liegt eine lokale Klasse vor. Im Fall einer lokalen Klasse, kann die umgebende Klasse nicht mehr auf die Methoden und Attribute der inneren Klasse zugreifen, da der Name der Klasse außerhalb der Methode nicht bekannt ist. Dies ist analog zu einer lokalen Variablen, die man ebenfalls nicht von außen sehen kann.
Genauso wie die nichtstatischen Element-Klassen kann ein Objekt der lokalen Klasse nur im Kontext eines Objektes der umgebenden Klasse existieren. Wenn sie sich in einer normalen Methode befindet, ist dieses das Objekt, auf das die this
-Referenz der Methode verweist.
Wenn die lokale Klasse in einer statischen Methode deklariert wird, kann sie nur noch auf statische Methoden und statische Felder der äußeren Klasse zugreifen, da sie dann nicht mehr im Kontext einer Instanz der äußeren Klasse existiert.
- Zugriff auf alle Attribute und Methoden der äußeren Klasse (Ausnahme lokale Klassen in statischen Methoden)
- Zugriff auf alle final Variablen der Methode, in der sie deklariert wurde
- Sichtbarkeit (
public
,private
,protected
oder default) kann nicht angegeben werden - Deklaration muss vor Benutzung erfolgen
Für die lokale Klasse kann keine Sichtbarkeit angegeben werden, da sie bereits die geringst mögliche Sichtbarkeit hat: Sie ist nur innerhalb der Methode sichtbar und liegt damit sogar noch unter private
.
Beispiel: Lokale Klasse
public class LocalBeispiel {
public static void main(String[] args) {
class LocalClass {
public String toString() {
return "Ich bin lokal";
}
}
LocalClass local = new LocalClass();
System.out.println(local.toString());
}
}
Ich bin lokal
Innerhalb der umgebenden Methode ist der Namen der Klasse bekannt und kann sowohl für Referenzvariablen als auch für die Erzeugung von Objekten verwendet werden. Außerhalb der Methode ist die Klasse nicht sichtbar.
Da bei lokalen Klassen die Deklaration vor der Benutzung erfolgen muss, kann man die Objekterzeugung im Beispiel nicht vor die Deklaration mit class LocalClass {...}
ziehen.
Beispiel: Zugriff auf lokale Variablen
public class LocalMitVariable {
public static void main(String[] args) {
final String ausgabe = "Ich bin lokal";
class LocalClass {
public String toString() {
return ausgabe;
}
}
LocalClass local = new LocalClass();
System.out.println(local.toString());
}
}
Ich bin lokal
Die lokale Klasse hat Zugriff auf finale lokale Variablen der umgebenden Methode. Dies ist auf den ersten Blick verwirrend, da lokale Variablen auf dem Stack liegen, Objekte aber auf dem Heap. Lokale Variablen werden vernichtet, sobald die Methode zurückkehrt. Da aber die Methode ein Objekt der lokalen Klasse zurückgeben kann, ist es möglich, dass das Objekt der lokalen Klasse länger lebt als die Methode selbst. Dies würde aber bedeuten, dass die lokalen Variablen vernichtet würden, obwohl das Objekt sie noch benötigt. In Programmiersprachen wie C, gilt es als schwerwiegender Programmierfehler Referenzen auf Variablen auf dem Stack außerhalb der Methode zu verwenden.
Java löst diese paradoxe Situation durch einen Kunstgriff: auf dem Stack können nur Referenzen und primitive Daten liegen. Durch die Bedingung, dass nur finale Variablen aus der lokalen Klasse genutzt werden können, wird gewährleistet, dass sie sich nach der Erzeugung des Objektes der lokalen Klasse nicht mehr ändern können. Wenn es Referenzen sind, liegt das referenzierte Objekt ohnehin auf dem Heap und lebt beliebig lang. Daher wird bei der Erzeugung des Objektes der lokalen Klasse einfach eine Kopie der Variablen in dem Objekt selbst gespeichert. Hierfür werden spezielle (unsichtbare) Attribute erzeugt. Diese Kopie ist dann bezüglich der Lebensdauer von der Methode entkoppelt, sodass das Problem gelöst ist. Das final
garantiert, dass die Kopie und das Original der Variable sich nicht unterscheiden können.
Beispiel: Zugriff auf Instanzvariablen
public class LocalMitVariableUndInstanz {
private String variable = "Ich bin nicht lokal";
public void doIt() {
final String ausgabe = "Ich bin lokal";
class LocalClass {
public String toString() {
return ausgabe + ", " + variable;
}
}
LocalClass local = new LocalClass();
System.out.println(local.toString());
}
}
Ich bin lokal, Ich bin nicht lokal
Die lokale Klasse hat Zugriff auf Instanz-Variablen der umgebenden Klasse. Die Verwendung einer expliziten this
-Referenz auf das Objekt der umgebenden Klasse ist hier nur nötig, wenn der Name der Variable innerhalb der Methode oder innerhalb der lokalen Klasse überdeckt wird.
Beispiel: Ausbruch des Objekts
public class Escape {
public static Object escape() {
class Papillon {
public String toString() {
return "Ich bin geflohen";
}
}
return new Papillon();
}
}
Object o = Escape.escape();
System.out.println(o.toString());
Ich bin geflohen
Obwohl die lokale Klasse außerhalb der Methode nicht sichtbar ist, können Objekte dieser Klasse die Methode verlassen und zurückgegeben werden. Der dynamische Typ ist dann für den Außenstehenden nicht verwendbar (da nicht sichtbar), sondern er kann das Objekt nur über eine Referenz von einem Typ manipulieren, der in der Vererbungshierarchie über der lokalen Klasse steht und der ihm bekannt ist – im vorliegenden Beispiel Object
.
public class Escape {
public static Object escape() {
final String text = "Ich bin geflohen";
class Papillon {
public String toString() {
return text;
}
}
return new Papillon();
}
}
Object o = Escape.escape();
System.out.println(o.toString());
Ich bin geflohen