Java Lokale Klassen
Klassen in Methodenrümpfen in Java deklarieren mit lokalen inneren Klassen und Zugriff auf effektiv finale lokale Variablen.
Eine lokale Klasse ist eine Klasse, die innerhalb eines Methodenrumpfes (oder eines Konstruktors oder eines Initialisierungsblocks) deklariert wird. Sie ist auf den Block beschränkt, in dem sie deklariert wird — nichts außerhalb dieses Blocks kann sie namentlich erwähnen. Ansonsten verhält sie sich ähnlich wie eine innere Klasse, mit Zugriff auf die Member der umschließenden Instanz und auf die effektiv finalen lokalen Variablen der Methode.
Lokale Klassen sind im modernen Java selten. Lambdas haben ihre Hauptanwendungsfälle für Einzel-Methoden-Callbacks ersetzt, und anonyme Klassen sind für einmalige Implementierungen meist kürzer. Eine lokale Klasse ist jedoch gelegentlich die sauberste Option, wenn Sie einen benannten Typ benötigen, der an der Logik der umschließenden Methode teilnimmt und anderswo nicht nützlich ist.
Wenn Sie die anderen Mitglieder der verschachtelten Klassenfamilie noch nicht kennengelernt haben, legen die Kapitel zur Übersicht über verschachtelte Klassen und zu inneren Klassen die unten verwendeten Begriffe fest.
Deklaration
Eine Klassendeklaration innerhalb eines Methodenrumpfes:
public void process(List<String> lines) {
class Counter {
int n = 0;
void inc() { n++; }
}
Counter c = new Counter();
for (String s : lines) if (!s.isBlank()) c.inc();
System.out.println("non-blank lines: " + c.n);
}Außerhalb von process kann niemand Counter sehen — der Name existiert nicht über die schließende geschweifte Klammer der Methode hinaus. Innen verwenden Sie sie wie jede andere Klasse.
Warum eine lokale Klasse statt einer anonymen Klasse?
Eine lokale Klasse hat einen echten Namen, was Ihnen einige Dinge ermöglicht, die eine anonyme Klasse nicht kann:
- Ein Konstruktor. Sie können ihm Parameter geben, Validierungen schreiben und mehrere Konstruktoren haben.
- Mehrere Instanzen. Da die Klasse einen Namen hat, können Sie
new Counter()mehr als einmal schreiben. Eine anonyme Klassendefinition erstellt pro Ausdruck nur eine Instanz. - Selbstreferenz.
Counterkann sich selbst als Parameter entgegennehmen, einCounter next-Feld halten, rekursieren — alles, was benannte Typen können. - Lesbarkeit. Ein Name wie
Counterdokumentiert, wofür der Helfer gedacht ist. Anonymenew Object() { ... }-Blöcke sind schwerer zu überfliegen.
Zugriff auf den umschließenden Zustand
Lokale Klassen können:
- Felder der umschließenden Instanz lesen und schreiben (wenn die umschließende Methode nicht statisch ist).
- Instanzmethoden der umschließenden Klasse aufrufen.
- Die finalen oder effektiv finalen lokalen Variablen und Parameter der umschließenden Methode lesen — aber nicht neu zuweisen.
void run(int multiplier) {
class Scaler {
int scale(int x) { return x * multiplier; } // captures the parameter
}
System.out.println(new Scaler().scale(7));
}multiplier wird als Feld in die synthetische Klasse eingebunden. Die Anforderung „effektiv final" ist der Grund — wenn multiplier innerhalb von run nach der Erfassung durch Scaler neu zugewiesen werden könnte, würden die beiden stillschweigend unterschiedliche Werte haben.
In einer statischen Methode
In einer static-Methode ist die lokale Klasse implizit statisch — sie hat keine umschließende Instanz, auf die sie sich beziehen kann:
public static int demo() {
class Helper {
int square(int n) { return n * n; }
}
return new Helper().square(7);
}Es gibt hier kein Outer.this, da die umschließende Methode statisch ist. Helper kann immer noch effektiv finale lokale Variablen aus demo erfassen, nur keine Instanzfelder eines umschließenden Objekts, das nicht existiert.
Wann man sie tatsächlich verwendet
Konkrete Fälle, in denen eine lokale Klasse die Alternativen tatsächlich übertrifft:
- Der Helfer hat mehr als eine Methode, und Sie möchten die Methoden lieber unter einem klaren Namen gruppiert sehen als über anonyme Klassen-Boilerplate verteilt.
- Der Helfer benötigt einen Konstruktor, um seine Einrichtung zu validieren.
- Der Helfer rekursiert oder hält Referenzen auf andere Instanzen seines eigenen Typs.
Wenn ein Lambda oder eine kurze anonyme Klasse ausreicht, bevorzugen Sie das. Lokale Klassen sind ein Nischenwerkzeug.
Modifikatoren
Eine lokale Klasse akzeptiert nur eine begrenzte Anzahl von Modifikatoren:
final— markiert die Klasse als nicht erweiterbar. Sie hat bereits keinen Namen für äußeren Code, der sie erweitern könnte, daher ist dies meist eine Absichtserklärung.abstract— erlaubt, aber selten: Sie müssten eine zweite lokale Klasse im selben Block erstellen, die sie erweitert.- Zugriffsmodifikatoren (
public,protected,private) sind nicht erlaubt. Eine lokale Klasse lebt vollständig innerhalb eines Blocks, daher gibt es keinen Gültigkeitsbereich außerhalb dieses Blocks, von dem aus die Sichtbarkeit überhaupt gesteuert werden könnte.
Sie kann auch nicht direkt als static deklariert werden. Ob sie eine umschließende Instanz erfasst, hängt davon ab, ob die umgebende Methode statisch ist, wie oben gezeigt — nicht von einem Schlüsselwort.
Ein ausgearbeitetes Beispiel
Was kommt als Nächstes
Damit ist die Tour durch die verschachtelten Klassen abgeschlossen — und der größte Teil von Javas klassischer OOP-Maschinerie. Der nächste Abschnitt von Teil 6 befasst sich mit den besonderen Klassentypen: Typen, die Java für spezifische Datenformen bereitstellt, beginnend mit enum für feste Mengen von Konstanten. Weiter zu Java Enums.