static Keyword
The static keyword in Java lets you attach a field, method, block, or nested class directly to the class itself rather than to any particular object. That means you can use it without ever creating an instance — and every instance that does exist shares the same static member.
Why static Exists
When you define a regular field, each object gets its own private copy of that field. Sometimes that is exactly what you want. But sometimes a value naturally belongs to the whole class — think of a counter tracking how many objects have been created, or a utility method like Math.sqrt() that has nothing to do with an individual object’s state. The static keyword is Java’s tool for those situations.
Static Variables (Class Variables)
A static variable has one single copy in memory, shared across all instances of the class.
public class Counter {
static int count = 0; // one copy, shared by all instances
String name;
Counter(String name) {
this.name = name;
count++; // every constructor call increments the shared counter
}
}
public class Main {
public static void main(String[] args) {
Counter a = new Counter("Alice");
Counter b = new Counter("Bob");
Counter c = new Counter("Carol");
System.out.println("Objects created: " + Counter.count);
}
}
Output:
Objects created: 3
Notice the access style: Counter.count — you reference the class, not an instance. You can access a static variable through an instance reference (a.count), but that is misleading and most style guides (and IDEs) warn against it.
Tip: Use
ClassName.staticMemberfor clarity. Accessing statics through an instance reference makes it look instance-specific when it is not.
Static Methods
A static method belongs to the class, not to any object. You call it via the class name, and it cannot reference this or access instance (non-static) fields directly.
public class MathUtils {
// static helper — no state needed
public static int square(int n) {
return n * n;
}
public static boolean isEven(int n) {
return n % 2 == 0;
}
}
public class Main {
public static void main(String[] args) {
System.out.println(MathUtils.square(7)); // 49
System.out.println(MathUtils.isEven(4)); // true
}
}
Output:
49
true
The classic example you see every day is main itself:
public static void main(String[] args) { ... }
The JVM calls main before any object exists, so it must be static.
Rules for Static Methods
| What a static method can do | What it cannot do |
|---|---|
| Access other static fields and methods | Access instance fields (this.x) |
| Create new objects | Use the this keyword |
| Call static methods from other classes | Call non-static methods directly |
| Be overloaded | Be overridden (only hidden — see Static & Dynamic Binding) |
Note: Static methods can access instance members if they receive an object reference as a parameter — they just cannot implicitly assume any particular object.
Static Blocks (Static Initializer)
A static block runs once, when the class is first loaded by the JVM, before any objects are created. Use it to perform complex initialization of static variables.
public class Config {
static final String DB_URL;
static final int MAX_CONNECTIONS;
static {
// runs once when the class is loaded
DB_URL = "jdbc:mysql://localhost:3306/app";
MAX_CONNECTIONS = Integer.parseInt(
System.getProperty("db.maxConn", "10")
);
System.out.println("Config initialized.");
}
}
public class Main {
public static void main(String[] args) {
System.out.println(Config.DB_URL);
System.out.println(Config.MAX_CONNECTIONS);
}
}
Output:
Config initialized.
jdbc:mysql://localhost:3306/app
10
You can have multiple static blocks in a class; they execute in top-to-bottom order.
Tip: Keep static blocks short and side-effect-free where possible. Complex logic in static initializers can make bugs hard to trace because stack traces point inside the class-loading sequence.
Static Nested Classes
A nested class marked static does not hold a reference to its enclosing class instance. You can create it independently.
public class Outer {
static int outerStatic = 42;
int outerInstance = 100;
static class Inner {
void display() {
// can access static members of Outer
System.out.println("Outer static: " + outerStatic);
// cannot access outerInstance — no Outer reference
}
}
}
public class Main {
public static void main(String[] args) {
Outer.Inner inner = new Outer.Inner(); // no Outer instance needed
inner.display();
}
}
Output:
Outer static: 42
Compare this to a regular member inner class, which always requires an enclosing instance. See Inner Classes for the full picture.
Static Import
Java’s static import feature lets you use static members without the class name prefix. It is handy for frequently used constants or utility methods:
import static java.lang.Math.PI;
import static java.lang.Math.sqrt;
public class Circle {
public static double area(double radius) {
return PI * radius * radius; // no Math.PI
}
public static double hypotenuse(double a, double b) {
return sqrt(a * a + b * b); // no Math.sqrt
}
}
Warning: Overusing static imports makes code harder to read — a reader cannot tell where
sqrtcomes from without checking the import list. Reserve it for widely recognised constants likePIor for test assertions (import static org.junit.Assert.*). See Static Import for more detail.
Common Patterns Using static
Singleton
public class AppSettings {
private static AppSettings instance;
private AppSettings() {} // private constructor
public static AppSettings getInstance() {
if (instance == null) {
instance = new AppSettings();
}
return instance;
}
}
Constants
Combine static with final to create class-level constants:
public class HttpStatus {
public static final int OK = 200;
public static final int NOT_FOUND = 404;
public static final int SERVER_ERROR = 500;
}
Factory / Utility Methods
static methods that return an object are a clean alternative to constructors:
public class Color {
private int r, g, b;
private Color(int r, int g, int b) {
this.r = r; this.g = g; this.b = b;
}
public static Color ofRGB(int r, int g, int b) {
return new Color(r, g, b);
}
public static Color red() { return new Color(255, 0, 0); }
public static Color green() { return new Color(0, 128, 0); }
}
Under the Hood
Where Static Variables Live in the JVM
Prior to Java 8, static variables were stored in the PermGen space of the heap. From Java 8 onwards, PermGen was replaced by Metaspace (native memory), but static variable values actually live in the heap area alongside the Class object that represents the class. The reference to each static field is held by the class’s internal data structure in Metaspace.
Class Loading and the static Block
When the JVM class loader first resolves a class reference, it:
- Loads the
.classbytecode into memory. - Links it (verifies bytecode, allocates memory for static variables with default values).
- Initialises it — runs all static initialisers and assigns their values, in source order.
This happens at most once per class per class loader. The JVM guarantees it is thread-safe: if two threads race to trigger class initialisation, one blocks until the first finishes.
Static vs Instance Method Dispatch
Instance method calls in the JVM use invokevirtual or invokeinterface, which involve a vtable lookup for runtime polymorphism. Static method calls use invokestatic, which resolves the target method at compile time. There is no dynamic dispatch — static methods cannot be overridden (they can only be hidden). This makes static calls marginally faster, but the difference is rarely measurable in real code. See vtable & Dynamic Dispatch for the full breakdown.
Memory Implication
Because static variables exist for the entire lifetime of the class (not just one object), they are a common source of memory leaks — especially if a static field holds a collection that keeps growing. Always ask: should this really outlive all instances?
Quick Reference
| Member | Belongs to | Shares across instances | Can access instance members directly |
|---|---|---|---|
| Instance field | Object | No | Yes |
| Static field | Class | Yes | No |
| Instance method | Object | N/A | Yes |
| Static method | Class | N/A | No |
| Static block | Class (init) | N/A | No |
| Static nested class | Class | N/A | Only static members of outer |
Related Topics
- this Keyword — the counterpart to
static: refers to the current instance within instance methods - final Keyword — combine with
staticto create compile-time constants - Static & Dynamic Binding — how the JVM resolves static vs instance method calls at the bytecode level
- Class Loaders & Class Loading — how the JVM loads classes and triggers static initialisation
- Inner Classes — how static nested classes differ from inner classes
- Static Import — use static members without repeating the class name