Static Variables in Java β€” Class-level State

A static variable (class variable) belongs to the class itself β€” one copy, shared by every instance and accessible without any instance. Use it for constants and immutable shared data. Mutable static state is almost always a mistake.

Declaration

public class Counter {
    private static int total;            // ONE slot for the whole class
    private int mine;                     // one per instance

    public void increment() {
        total++;
        mine++;
    }
}

Constants β€” static final

public class Config {
    public static final int    MAX_RETRY = 3;
    public static final String BASE_URL  = "https://api.example.com";
    public static final Duration TIMEOUT = Duration.ofSeconds(30);
}

The canonical form for a constant. Conventional naming: UPPER_SNAKE_CASE.

Static initialiser block

public class Country {
    private static final Map<String, String> CODES;

    static {
        var m = new HashMap<String, String>();
        m.put("fr", "France");
        m.put("de", "Germany");
        CODES = Map.copyOf(m);
    }
}

Runs once, at class loading. If it throws, the class can't be used β€” you'll see ExceptionInInitializerError.

Default values

Same as instance fields: 0, false, null. Like instance fields, static fields don't need explicit initialisation.

Access

Math.PI;                        // βœ… ClassName.field β€” preferred
Config.MAX_RETRY;

Counter c = new Counter();
c.total;                         // βœ… compiles, bad style β€” obscures staticness

The problem with mutable static state

  • Thread-safety by default is broken β€” every thread sees the same field without coordination.
  • Hard to test β€” test pollution when one test changes the state.
  • Hidden dependencies β€” a method that reads SomeClass.config pretends to be pure but depends on a global.

Prefer dependency injection for shared state. Use static only for constants and pure functions.

Memory and class unloading

Static fields live as long as the class loader that loaded them. In long-running applications (app servers, web frameworks with hot reload), a static field holding a big structure can leak memory if the class loader can't be released.

Common mistakes

  • Mutable static state across threads β€” race conditions.
  • Static collections as caches without eviction β€” silent memory leak.
  • Forgetting final on constants β€” public static int MAX = 100; is a global mutable. Add final.

Related

Pillar: Variables in Java. See also static keyword, final variables.