Java Variable Scope
Understand where a Java variable is visible — local, instance, class (static), and block scope.
The scope of a variable is the region of the program where you're allowed to use its name. A name declared inside one method isn't visible from another; a name declared inside a for loop isn't visible after the loop. The compiler enforces these rules strictly — try to reach a name outside its scope and your code won't compile.
Java has three main kinds of variables, each with its own scope: local variables (including parameters), instance fields, and class fields. This chapter focuses on local scope since that's what shapes the methods you've been writing.
Local variables
A local variable is declared inside a method or a block, and is visible only from the point of declaration to the end of the enclosing block:
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()Local variables are not initialized by Java — you must assign a value before reading. The compiler tracks definite assignment and refuses to compile a read of a possibly-unassigned local:
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
}This is different from instance and class fields, which Java does default-initialize (numbers to 0, boolean to false, object references to null).
Block scope
Curly braces define a block. Variables declared inside a block are visible only inside that block, including nested blocks but not outside:
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
}This applies to if, for, while, do-while, switch, and to bare { ... } blocks you write for grouping. A for's loop variable is in scope only inside the loop:
for (int i = 0; i < 3; i++) {
System.out.println(i);
}
// System.out.println(i); // ERROR: i is out of scopeIf you need the index after the loop, declare i outside:
int i = 0;
for (; i < 3; i++) {
System.out.println(i);
}
System.out.println("stopped at " + i);Method parameters
Parameters are local variables that happen to be initialized by the caller. Their scope is the entire method body, from the opening brace to the closing one:
public static int square(int n) { // n is in scope from here...
return n * n;
} // ...to hereEach call gets its own set of parameter slots, so recursive calls don't interfere with each other.
Shadowing
Java forbids declaring a local variable with the same name as one that's already in scope in the same block or an enclosing block of the same method:
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
}
}This is stricter than what many languages allow — Java assumes that re-using a name inside a method is a mistake. (Instance and class fields can be shadowed by local variables of the same name; we'll get to that in the OOP part of the book.)
Note that two sibling blocks can reuse a name, because their scopes don't overlap — neither is visible inside the other:
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 */ }
}Lifetime vs. scope
Scope is where you can use the name. Lifetime is how long the underlying storage exists. They usually line up — when a local goes out of scope, its slot is gone — but for objects the distinction matters:
public static String makeName() {
String s = new String("Ada"); // s in scope here
return s;
} // s out of scope, but the String object lives onThe variable s disappears, but the String object it referenced is still alive — the caller holds a reference, so the garbage collector won't reclaim it. Local variables limit names, not object lifetimes.
A glimpse of instance and class fields
Inside a class, alongside methods, you can declare fields — variables whose scope is the whole class. There are two flavors:
- Instance fields belong to each object created from the class. Each
Doghas its ownnameandage. - Class fields (declared
static) belong to the class itself; there's one shared copy.
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
}
}We won't go deeper here — Classes and Objects introduces the class itself, and Class Attributes covers instance fields properly. The short version: fields are visible everywhere in the class; locals are visible only in the block they're declared in.
A worked example
What's next
Scope tells you where a name lives. The next question — once you've passed an argument into a method — is what the method actually has. The pass-by-value chapter clears up the most common confusion in Java: what's really going on when you pass an object reference.