Introduction To Static Members in Java
Static Members in Java
Every field and method you have written so far has belonged to an individual object; each Car had its own speed, each Student had its own name. Static members break that pattern: they belong to the class itself, shared by every object of that class, rather than duplicated per instance.
Static Variables and Static Methods
A static variable is stored exactly once per class, no matter how many objects you create. Every instance reads and writes the very same piece of memory, so a change made through one object is immediately visible through every other object of that class.
class Counter {
static int count = 0; // shared by every Counter object
Counter() {
count++;
}
}
Counter c1 = new Counter();
Counter c2 = new Counter();
Counter c3 = new Counter();
System.out.println(Counter.count); // 3 — shared across all three objects
A static method belongs to the class in the same way, and crucially, it can be called without ever creating an object. This is exactly why Java's main(String[] args) method must be static: the JVM needs to invoke it before any object of your class exists.
class MathHelper {
static int square(int n) {
return n * n;
}
}
int result = MathHelper.square(5); // called directly on the class, no object needed
A static method can only directly access other static members. It has no this reference, since it is not tied to any particular object, so it cannot reach instance fields or call instance methods without first being handed a specific object to operate on.
Static Blocks and Initialisation
A static block is a chunk of code that runs exactly once, automatically, when the class is first loaded into memory, before any object is created and before main() itself runs if the block lives in the entry-point class. It is most often used to set up static fields that need more than a simple one-line assignment.
class DatabaseConfig {
static String url;
static int maxConnections;
static {
System.out.println("Loading database configuration...");
url = "jdbc:mysql://localhost:3306/mydb";
maxConnections = 50;
}
}
// The static block runs once, the very first time DatabaseConfig is referenced
System.out.println(DatabaseConfig.url);
A class can have multiple static blocks, and Java executes them in the exact order they appear in the source file, top to bottom, all before any static method or main() in that class is reached.
When to Use Static vs Instance Members
Use Static When... | Use Instance When... |
The value or behaviour is shared identically across all objects (e.g. a constant, a counter of all objects created) | The value or behaviour genuinely differs per object (e.g. a Student's name, a Car's current speed) |
The method is a pure utility that doesn't depend on any object's state (e.g. Math.sqrt()) | The method needs to read or modify a specific object's fields |
You need to access something before any object exists (e.g. configuration loaded at startup) | The data represents a real, individual real-world entity's properties |
• A common beginner mistake is overusing static, turning every helper method static 'just in case', which often signals the method should actually belong to a properly designed object instead.
• Static fields that are mutable and shared across the whole application can introduce subtle bugs in multi-threaded programs, since multiple threads may read and write the same static field at the same time, without realising they are sharing it.
• It is good practice to mark static fields that should never change as final as well, combining static final to create a true class-wide constant.
class Constants {
static final double TAX_RATE = 0.18; // shared, and cannot be reassigned
}
Did You Know?
Static methods are resolved entirely at compile time based on the reference type, not the actual object, which is why static methods cannot be truly overridden the way instance methods can. A subclass can declare a static method with the identical signature, but this only hides the superclass version rather than overriding it, and which one runs depends on the reference type used to call it, not the object's real class.










