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.

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.)

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 — the Classes and Objects part covers 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?