Lokale Klassen
Eine lokale Klasse (local class) wird – anders als bis jetzt kennengelernt – nicht im Rumpf einer Klasse definiert, sondern direkt in einem Anweisungsblock (Konstruktor, Methode, …). Die Sichtbarkeit der lokalen Klasse darf nicht verändert werden, und sie darf keine statischen Attribute oder Methoden enthalten, die nicht als final deklariert wurden. Zugreifen können solche Klassen auf die Attribute und Methoden der äußeren Klasse, sowie auf die lokalen Variablen und Übergabeparameter, die als final gekennzeichnet wurden. Sollte eine lokale Klasse allerdings in einem statischen Anweisungsblock definiert worden sein, so ist ein Zugriff auf die Objektattribute bzw. Objektmethoden der äußeren Klasse selbstverständlich nicht möglich.
package de.inner;
public class LocalTest {
o
private static int z = 0;
o
public static void main(String[] args) {
o
final int y = 3;
o
class Local {
private int i = 1;
private int z = 4;
o
Local() {
this.i = LocalTest.z;
}
o
private void printI() {
System.out.println("I = " + this.i);
}
o
private void printY() {
System.out.println("Y = " + y);
}
o
private void printZ() {
System.out.println("Z = " + this.z);
}
}
Local loc = new Local();
loc.printI();
loc.printY();
loc.printZ();
}
}
Anonyme, innere Klassen
Diese Klassen (anonymous classes) sind im Prinzip keine eigene Klassen, sondern Klassen, die von anderen Klassen erben und selbige manipulieren/erweitern. Somit können z. B. Instanzen von abstrakten Klassen oder Interfaces erstellt werden, ohne extra eine Klasse zu programmieren, die von dieser Klasse erbt/dieses Interface implementiert. Als Beispiel dient diesmal das Interface CharSequence, welches Sie diverse Methoden zum Auslesen von Zeichenketten implementieren lässt.
package de.inner;
public class Anonym {
public static void main(String[] args) {
o
final String aValue = "Java Blog Buch";
o
CharSequence seq = new CharSequence() {
private String content = null;
// Exemplarinitialisierer anstelle
// eines Konstruktors
{
this.content = aValue;
}
o
public char charAt(int index) {
return this.content.charAt(index);
}
public int length() {
return this.content.length();
}
public CharSequence subSequence(int start, int end) {
return this.content.subSequence(start, end);
}
o
public String toString() {
return this.content;
}
};
System.out.println(seq);
}
}
Eine anonyme, innere Klasse kann keine weiteren Interfaces implementieren, oder von anderen Klassen erben. Auch ist es nicht möglich einen eigenen Konstruktor zu definieren. Als Ersatz können Sie in diesen Klassen Exemplarinitialisierer (Instanz Initialisierer) verwenden (s. o. und das Kapitel über statische Initialisierer). Was statische Attribute und Methoden angeht, bestehen die selben Einschränkungen wie bei lokalen Klassen.
Beliebte Einsatzorte für anonyme, innere Klassen sind Threads und Listener (siehe entsprechende Kapitel).
Implementierung von Interfaces und Vererbung
Ausgenommen der anonymen, inneren Klasse, können alle anderen inneren Klassen auch von anderen Klassen erben oder Interfaces implementieren. Dabei gehen Sie exakt so wie bei normalen Klassen vor.
public class AClass {
public class InnerClass extends AnOtherClass implements AnInterface {
...
}
}
Übersetzung des Compilers
Der Compiler erzeugt automatisch für jede innere Klasse eine neue .class-Datei. Dabei wird eine bestimmte Formatierung verwendet. Statische, verschachtelte Klassen und innere Klassen werden in der Form „AeussereKlasse$InnereKlasse“ gespeichert (z. B. InnerTest$Inner.class). Lokale Klassen erhalten das Format „AeussereKlasse$FortlaufendeNummer$LokaleKlasse“ (z. B. LokaleKlasse$1$Local.class). Innere, anonyme Klassen werden hingegen nur durch „AeussereKlasse$FortlaufendeNummer“ definiert (z. B. Anonym$1.class).
Import
Um innere Klassen oder statische, verschachtelte Klassen in anderen Klassen zu verwenden, können Sie sie auf drei unterschiedliche Arten ansprechen.
pfad.zur.klasse.AeussereKlasse.InnereKlasse.doSomething();
import package.zur.klasse.AeussereKlasse;
...
{
AeussereKlasse.InnereKlasse.doSomething();
}
import package.zur.klasse.AeussereKlasse.InnereKlasse;
...
{
InnereKlasse.doSomething();
}
