1. Lokale Klasse
Eine lokale Klasse – das ist eine Klasse, die innerhalb einer Methode deklariert wird (oder sogar innerhalb eines Codeblocks, zum Beispiel in einer Schleife oder in einem if-Block). Sie ist nur innerhalb dieser Methode sichtbar und nutzbar, außerhalb – als hätte es sie nie gegeben. Im Gegensatz zu anonymen Klassen hat eine lokale Klasse einen Namen (wenn auch einen einfachen), kann mehrere Methoden und sogar Felder enthalten.
Wenn man eine Analogie zieht – stellen Sie sich vor, Sie kochen nach einem Rezept ein aufwändiges Gericht. In einem der Schritte müssen Sie eine besondere Sauce zubereiten, die nur in diesem Rezept verwendet wird und sonst nirgends. Anstatt dafür ein eigenes „Kochbuch“ zu veröffentlichen, beschreiben Sie die Zubereitung einfach direkt im Hauptrezept. Eine lokale Klasse funktioniert genauso – das ist ein „Rezept im Rezept“, das nur in einer ganz bestimmten Methode gebraucht wird.
Beispiel: Deklaration einer lokalen Klasse
public class Outer {
void someMethod() {
class Local {
void print() {
System.out.println("Hello from Local!");
}
}
Local local = new Local();
local.print();
}
}
Hier wird die Klasse Local innerhalb der Methode someMethod der Klasse Outer deklariert. Sie existiert nur in dieser Methode und ist von außen nicht sichtbar.
Syntax lokaler Klassen
Die Deklaration einer lokalen Klasse ähnelt einer normalen Klassendeklaration, nur dass sie innerhalb einer Methode erfolgt:
void myMethod() {
class MyLocalClass {
void doSomething() {
System.out.println("Die lokale Klasse funktioniert!");
}
}
MyLocalClass obj = new MyLocalClass();
obj.doSomething();
}
Syntaxbesonderheiten:
- Eine lokale Klasse kann innerhalb beliebiger Methoden, Konstruktoren oder sogar Initialisierungsblöcke deklariert werden.
- Eine lokale Klasse muss einen Namen haben (im Gegensatz zu anonymen Klassen).
- Eine lokale Klasse kann nicht mit Zugriffsmodifikatoren (public, private, protected) oder dem Modifikator static deklariert werden.
- Eine lokale Klasse kann Interfaces implementieren oder von anderen Klassen erben.
Vergleich von Klassentypen:
public class Example {
// 1. Normale Klasse (in separater Datei)
// class RegularClass { ... }
// 2. Innere Klasse (in einer Klasse)
class InnerClass { }
// 3. Statische verschachtelte Klasse (in einer Klasse)
static class NestedClass { }
void method() {
// 4. Lokale Klasse (in einer Methode)
class LocalClass { }
// 5. Anonyme Klasse (in einer Methode, ohne Namen)
Object obj = new Object() { };
}
}
Lokale Klasse = benannte Klasse nur für diese Methode!
2. Besonderheiten lokaler Klassen
Zugriff auf Methodenvariablen
Eine lokale Klasse kann zugreifen auf:
- Felder der äußeren Klasse (auch wenn sie private sind).
- Nur auf final- oder effectively final-Variablen der umgebenden Methode.
Was bedeutet „effectively final“?
Das ist eine Variable, deren Wert nach der Initialisierung nicht mehr geändert wird. Zum Beispiel:
void foo() {
int x = 5; // effectively final
class L { void print() { System.out.println(x); } }
}
Wenn Sie später x = 10; schreiben würden, würde der Compiler einen Fehler melden.
Warum ist das so?
Das liegt daran, wie Java lokale Klassen „unter der Haube“ implementiert: Methodenvariablen werden tatsächlich in die lokale Klasse kopiert und nicht per Referenz gehalten. Könnte sich die Variable ändern, würde die lokale Klasse mit einer veralteten Kopie arbeiten – ein sicherer Weg zu Bugs und Kopfschmerzen.
Beispiel mit Zugriff auf Variablen
public class Outer {
private String secret = "Geheimnis!";
void revealSecret() {
String greeting = "Hallo,"; // effectively final
class Revealer {
void printSecret() {
System.out.println(greeting + " " + secret);
}
}
Revealer revealer = new Revealer();
revealer.printSecret();
}
}
3. Einsatz lokaler Klassen: wozu und wann?
Lokale Klassen sind kein Alltagswerkzeug, aber manchmal machen sie den Code klarer und kompakter. In folgenden Fällen lohnt sich ihr Einsatz:
- Hilfslogik, die nur zu einer Methode gehört.
Zum Beispiel, wenn in einer Methode eine komplexe Sortierung, Filterung oder eine temporäre Datenstruktur implementiert werden soll. - Kapselung, um die Klasse nicht mit unnötigen Typen zu überfrachten.
Wenn ein Typ nur an einer Stelle benötigt wird, warum ihn in der gesamten Klasse oder im gesamten Paket sichtbar machen? - Umsetzung von Entwurfsmustern, bei denen Hilfsobjekte nur lokal gebraucht werden.
Beispiel: Sortieren mit lokaler Klasse
Angenommen, Sie haben eine Liste von Namen und möchten sie nach der Länge sortieren. Sie können eine lokale Comparator-Klasse anlegen:
import java.util.*;
public class NameSorter {
public void sortNames(List<String> names) {
class LengthComparator implements Comparator<String> {
@Override
public int compare(String a, String b) {
return Integer.compare(a.length(), b.length());
}
}
Collections.sort(names, new LengthComparator());
}
}
Beispiel: temporäre Struktur
Manchmal braucht man eine Hilfsstruktur zur Verarbeitung von Daten in einer einzigen Methode:
void processScores(int[] scores) {
class ScoreInfo {
int score;
boolean passed;
ScoreInfo(int score) {
this.score = score;
this.passed = score >= 60;
}
}
for (int s : scores) {
ScoreInfo info = new ScoreInfo(s);
System.out.println("Note: " + info.score + ", bestanden: " + info.passed);
}
}
4. Lokale Klassen vs. anonyme Klassen
Man fragt sich manchmal: Wozu braucht man lokale Klassen, wenn es anonyme gibt? Schauen wir es uns an.
- Lokale Klasse – eine benannte Klasse, die man innerhalb einer Methode mehrfach verwenden kann; sie kann Felder, mehrere Methoden und sogar geschachtelte Klassen enthalten.
- Anonyme Klasse – eine einmalige Implementierung eines Interface oder einer Basisklasse, ohne Namen, in der Regel mit einer Methode (oder der Überschreibung von ein bis zwei Methoden).
Wann verwenden:
- Ist die Logik einfach und nur einmal erforderlich – verwenden Sie eine anonyme Klasse.
- Brauchen Sie mehr Methoden oder Felder oder soll die Klasse an mehreren Stellen der Methode verwendet werden – verwenden Sie eine lokale Klasse.
Vergleichsbeispiel
Anonyme Klasse:
Runnable r = new Runnable() {
@Override
public void run() {
System.out.println("Schnell und anonym!");
}
};
Lokale Klasse:
void doWork() {
class MyWorker implements Runnable {
@Override
public void run() {
System.out.println("Ich bin eine lokale Klasse!");
}
}
MyWorker worker = new MyWorker();
worker.run();
}
5. Einschränkungen und Besonderheiten lokaler Klassen
- Zugriffsmodifikatoren: Eine lokale Klasse kann nicht als public, private oder protected deklariert werden. Außerdem kann man kein static hinzufügen.
- Statische Member: Eine lokale Klasse darf keine statischen Member enthalten, außer Konstanten (static final).
- Sichtbarkeit: Eine lokale Klasse ist nur in dem Block sichtbar, in dem sie deklariert wurde.
- Verwendung von Generics-Typparametern: Eine lokale Klasse kann generisch sein, falls erforderlich.
- Schachtelung: Lokale Klassen können innerhalb anderer lokaler Klassen deklariert werden (aber übertreiben Sie es nicht, sonst wird der Code zur Matrjoschka).
6. Lokale Klassen in einer realen Anwendung
Führen wir unser Übungsprojekt fort. Angenommen, es gibt eine Klasse Quiz, die dem Benutzer Fragen stellt und Antworten prüft. Wir möchten innerhalb der Prüfmethode eine temporäre Klasse anlegen, die die Antwort des Benutzers und den Prüfstatus speichert.
Beispiel: Verwendung einer lokalen Klasse in der Anwendung
import java.util.Scanner;
public class Quiz {
private String question = "Hauptstadt von Frankreich?";
private String correctAnswer = "Paris";
public void runQuiz() {
Scanner scanner = new Scanner(System.in);
System.out.println(question);
String userAnswer = scanner.nextLine();
// Lokale Klasse zur Speicherung des Ergebnisses
class AnswerResult {
String answer;
boolean isCorrect;
AnswerResult(String answer) {
this.answer = answer;
this.isCorrect = answer.equalsIgnoreCase(correctAnswer);
}
void printResult() {
if (isCorrect) {
System.out.println("Richtig!");
} else {
System.out.println("Falsch, die richtige Antwort: " + correctAnswer);
}
}
}
AnswerResult result = new AnswerResult(userAnswer);
result.printResult();
}
}
Hier existiert die Klasse AnswerResult nur innerhalb der Methode runQuiz und wird sonst nirgends benötigt. Ein hervorragendes Praxisbeispiel für eine lokale Klasse!
7. Häufige Fehler im Umgang mit lokalen Klassen
Fehler Nr. 1: Versuch, auf eine Methodenvariable zuzugreifen, die nicht final oder nicht effectively final ist.
Wenn Sie eine Variable in der Methode deklarieren und ihren Wert nach der Verwendung in der lokalen Klasse ändern, meldet der Compiler sofort einen Fehler. Achten Sie stets darauf, dass solche Variablen nach der Initialisierung unverändert bleiben.
Fehler Nr. 2: Der Wunsch, Zugriffsmodifikatoren oder static hinzuzufügen.
Eine lokale Klasse kann nicht mit den Modifikatoren public, private, protected oder static deklariert werden. Wenn Sie das versuchen – meldet der Compiler einen Fehler.
Fehler Nr. 3: Versuch, eine lokale Klasse außerhalb der Methode zu verwenden.
Eine lokale Klasse lebt nur in der Methode (oder dem Block), in der sie deklariert wurde. Aus anderen Methoden oder von außerhalb der Klasse ist sie nicht zugänglich.
Fehler Nr. 4: Übermäßiger Einsatz lokaler Klassen für komplexe Logik.
Wenn Ihre lokale Klasse zu groß wird, viele Methoden oder Felder enthält – sollte sie vermutlich in eine eigene Klasse ausgelagert werden. Lokale Klassen sind für kompakte, unterstützende Aufgaben gedacht.
GO TO FULL VERSION