The <code>static</code> Keyword in Java
static attaches a member to the class itself instead of to instances. A static field is shared across every instance (and callers who don't even have one). A static method is called via ClassName.method() and has no this.
Static fields β one copy per class
public class Counter {
private static int total; // ONE slot, shared by all instances
private int mine; // one slot PER instance
public void increment() {
total++;
mine++;
}
public static int total() { return total; }
}
Static methods
public class MathUtils {
public static int square(int n) { return n * n; }
}
MathUtils.square(5); // no instance needed
Static methods can't access instance fields or call instance methods (they have no this). They also aren't polymorphic β the call is resolved at compile time.
Constants β static final
public class Config {
public static final int MAX_RETRY = 3;
public static final Duration TIMEOUT = Duration.ofSeconds(30);
}
Config.MAX_RETRY;
Static initialisers
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);
}
}
Static initialisers run once, when the class is first loaded. They run before any instance is created.
Static nested classes
public class Outer {
public static class Builder { ... } // no reference to Outer instance
}
var b = new Outer.Builder(); // no Outer needed
Unless a nested class truly needs access to the outer instance, make it static. A non-static inner class silently captures the outer reference β a memory leak waiting to happen.
Factory methods
public final class Money {
private final BigDecimal amount;
private final Currency currency;
private Money(BigDecimal amount, Currency currency) { ... }
public static Money usd(BigDecimal amount) {
return new Money(amount, Currency.getInstance("USD"));
}
public static Money zero() { return new Money(BigDecimal.ZERO, ...); }
}
Money.usd(new BigDecimal("10.50"));
Static imports
import static java.lang.Math.*;
import static org.assertj.core.api.Assertions.assertThat;
double r = sqrt(pow(x, 2) + pow(y, 2));
assertThat(value).isEqualTo(42);
Common mistakes
- Mutable static state β shared across threads, a race-condition gold mine. Prefer instance state with dependency injection.
- Static methods on everything β makes testing hard (can't mock). Use them for pure utilities only.
- Non-static inner class in a long-lived collection β retains the outer instance forever.
- Overriding
staticβ it's not overridden, it's hidden. Only instance methods are polymorphic.
Related
Pillar: Java keywords. See also static variables, static methods, final.