W3docs

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 scope

If 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 here

Each 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 on

The 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 Dog has its own name and age.
  • 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

java— editable, runs on the server

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.

Practice

Practice
Where is a variable declared inside an if block visible?
Where is a variable declared inside an if block visible?
Was this page helpful?