Java Variablenbereich (Scope)
Verstehe, wo eine Java-Variable sichtbar ist — lokaler, Instanz-, Klassen- (static) und Block-Scope.
Der Scope (Gültigkeitsbereich) einer Variable ist der Bereich des Programms, in dem du ihren Namen verwenden darfst. Ein Name, der innerhalb einer Methode deklariert wird, ist von einer anderen Methode aus nicht sichtbar; ein Name, der innerhalb einer for-Schleife deklariert wird, ist nach der Schleife nicht mehr sichtbar. Der Compiler erzwingt diese Regeln strikt — versuchst du, einen Namen außerhalb seines Scopes zu verwenden, lässt sich dein Code nicht kompilieren.
Java kennt drei Hauptarten von Variablen, jeweils mit eigenem Scope: lokale Variablen (einschließlich Parameter), Instanzfelder und Klassenfelder. Dieses Kapitel konzentriert sich auf den lokalen Scope, da er die Methoden prägt, die du bisher geschrieben hast.
Lokale Variablen
Eine lokale Variable wird innerhalb einer Methode oder eines Blocks deklariert und ist nur vom Deklarationspunkt bis zum Ende des umschließenden Blocks sichtbar:
public static int demo() {
int x = 1; // x is in scope from here...
System.out.println(x);
return x;
} // ...to here
// System.out.println(x); // ERROR: x not visible outside demo()Lokale Variablen werden von Java nicht initialisiert — du musst vor dem Lesen einen Wert zuweisen. Der Compiler verfolgt die definite assignment (eindeutige Zuweisung) und verweigert die Kompilierung beim Lesen einer möglicherweise nicht zugewiesenen lokalen Variable:
public static void unassigned() {
int n;
// System.out.println(n); // ERROR: variable n might not have been initialized
n = 5;
System.out.println(n); // OK now
}Dies unterscheidet sich von Instanz- und Klassenfeldern, die Java standardmäßig initialisiert (Zahlen auf 0, boolean auf false, Objektreferenzen auf null).
Block-Scope
Geschweifte Klammern definieren einen Block. Variablen, die innerhalb eines Blocks deklariert werden, sind nur innerhalb dieses Blocks sichtbar, einschließlich verschachtelter Blöcke, aber nicht außerhalb:
public static void blocks() {
int outer = 10;
if (outer > 0) {
int inner = 20;
System.out.println(outer + inner); // both visible
}
// System.out.println(inner); // ERROR: inner is out of scope here
}Dies gilt für if, for, while, do-while, switch und für reine { ... }-Blöcke, die du zur Gruppierung schreibst. Die Schleifenvariable einer for-Schleife gilt nur innerhalb der Schleife:
for (int i = 0; i < 3; i++) {
System.out.println(i);
}
// System.out.println(i); // ERROR: i is out of scopeWenn du den Index nach der Schleife benötigst, deklariere i außerhalb:
int i = 0;
for (; i < 3; i++) {
System.out.println(i);
}
System.out.println("stopped at " + i);Methodenparameter
Parameter sind lokale Variablen, die zufällig vom Aufrufer initialisiert werden. Ihr Scope ist der gesamte Methodenrumpf, von der öffnenden geschweifte Klammer bis zur schließenden:
public static int square(int n) { // n is in scope from here...
return n * n;
} // ...to hereJeder Aufruf erhält seinen eigenen Satz an Parameterslots, sodass rekursive Aufrufe sich nicht gegenseitig beeinflussen.
Shadowing (Verdeckung)
Java verbietet die Deklaration einer lokalen Variable mit demselben Namen wie eine, die bereits im gleichen Block oder einem umschließenden Block derselben Methode in Scope ist:
public static void clash() {
int x = 1;
// int x = 2; // ERROR: variable x is already defined
if (true) {
// int x = 3; // ERROR: x is in scope from the outer block
}
}Dies ist strenger als in vielen anderen Sprachen — Java geht davon aus, dass die Wiederverwendung eines Namens innerhalb einer Methode ein Fehler ist. (Instanz- und Klassenfelder können von lokalen Variablen gleichen Namens verdeckt werden; dazu kommen wir im OOP-Teil des Buches.)
Beachte, dass zwei nebeneinanderliegende Blöcke einen Namen wiederverwenden können, weil ihre Scopes sich nicht überschneiden — keiner ist im anderen sichtbar:
public static void siblings() {
for (int i = 0; i < 3; i++) { /* first i */ }
for (int i = 0; i < 3; i++) { /* a fresh i — legal, the first is gone */ }
}Lebensdauer vs. Scope
Scope bezeichnet, wo du den Namen verwenden kannst. Lebensdauer beschreibt, wie lange der zugrundeliegende Speicher existiert. In der Regel stimmen sie überein — wenn eine lokale Variable den Scope verlässt, ist ihr Speicherplatz weg — bei Objekten ist die Unterscheidung jedoch wichtig:
public static String makeName() {
String s = new String("Ada"); // s in scope here
return s;
} // s out of scope, but the String object lives onDie Variable s verschwindet, aber das String-Objekt, auf das sie verwies, lebt weiter — der Aufrufer hält eine Referenz, sodass der Garbage Collector es nicht zurückfordert. Lokale Variablen begrenzen Namen, nicht Objektlebenszeiten.
Ein Blick auf Instanz- und Klassenfelder
Innerhalb einer Klasse, neben Methoden, kannst du Felder deklarieren — Variablen, deren Scope die gesamte Klasse umfasst. Es gibt zwei Arten:
- Instanzfelder gehören zu jedem Objekt, das aus der Klasse erstellt wird. Jedes
Dog-Objekt hat seinen eigenennameundage. - Klassenfelder (mit
staticdeklariert) gehören zur Klasse selbst; es gibt eine gemeinsam genutzte Kopie.
public class Counter {
private static int totalCreated = 0; // class field — one shared
private int value = 0; // instance field — one per Counter
public Counter() {
totalCreated++;
}
public void inc() {
value++; // refers to this instance's field
}
}Wir gehen hier nicht tiefer — Classes and Objects stellt die Klasse selbst vor, und Class Attributes behandelt Instanzfelder ausführlich. Kurzgefasst: Felder sind überall in der Klasse sichtbar; lokale Variablen nur in dem Block, in dem sie deklariert wurden.
Ein durchgearbeitetes Beispiel
Was kommt als Nächstes
Der Scope beschreibt, wo ein Name lebt. Die nächste Frage — sobald du ein Argument an eine Methode übergeben hast — ist, was die Methode tatsächlich erhält. Das Kapitel pass-by-value klärt die häufigste Verwirrung in Java: Was passiert eigentlich, wenn du eine Objektreferenz übergibst.