Static Nested Class in Java – Syntax, Uses and Examples
A static nested class is a class declared inside another class with the static modifier. It belongs to the outer class, not to any outer object, so it can be created without an instance of the outer class and holds no hidden reference to one. In practice it behaves like a top-level class that has been placed inside another for organisation and access control.
Static nested classes are the most common kind of nested class. This tutorial covers their syntax and access rules and three classic uses: builders, private implementation classes, and the lazy holder singleton.
1. Syntax
class Outer {
[access modifier] static class Nested {
// fields, constructors, methods, static members
}
}
Outer.Nested n = new Outer.Nested(); // no Outer object required
2. Access Rules
public class StaticNestedAccess {
private static String appName = "JavaByTechie"; // outer static field
private String user = "asha"; // outer instance field
static class Helper {
String describe(StaticNestedAccess outer) {
// appName: accessible directly (static, even though private)
// user: needs an explicit outer object
return appName + " user = " + outer.user;
}
}
public static void main(String[] args) {
Helper h = new Helper(); // no outer object needed
System.out.println(h.describe(new StaticNestedAccess()));
}
}
JavaByTechie user = asha
- A static nested class can access the outer class's static members directly, even private ones.
- To use outer instance members it needs an explicit reference to an outer object.
- The outer class can access the nested class's private members too.
- It can have any access modifier, be
finalorabstract, extend classes and implement interfaces.
3. Use 1: The Builder Pattern
A builder collects optional settings and then creates an immutable object. Nesting it as Pizza.Builder lets it call Pizza's private constructor:
public class BuilderPattern {
static class Pizza {
private final String size;
private final boolean extraCheese;
private final String[] toppings;
private Pizza(Builder b) { // only the Builder can construct
this.size = b.size;
this.extraCheese = b.extraCheese;
this.toppings = b.toppings;
}
// Static nested class: needs no Pizza object to exist
static class Builder {
private String size = "Medium";
private boolean extraCheese;
private String[] toppings = {};
Builder size(String size) { this.size = size; return this; }
Builder extraCheese() { this.extraCheese = true; return this; }
Builder toppings(String... toppings) { this.toppings = toppings; return this; }
Pizza build() { return new Pizza(this); } // private constructor OK
}
public String toString() {
return size + " pizza" + (extraCheese ? " + extra cheese" : "")
+ (toppings.length == 0 ? "" : " with " + String.join(", ", toppings));
}
}
public static void main(String[] args) {
Pizza p = new Pizza.Builder().size("Large").extraCheese().toppings("paneer", "onion").build();
System.out.println(p);
System.out.println(new Pizza.Builder().build());
}
}
Large pizza + extra cheese with paneer, onion Medium pizza
The JDK uses this naming style too, for example HttpRequest.Builder and Locale.Builder, and libraries such as Lombok generate it.
4. Use 2: Private Implementation Classes
Data structures use private static nested classes for nodes and entries. HashMap.Node and LinkedList.Node are examples from the JDK:
public class LinkedStack<T> {
// Private static nested class: an implementation detail, no outer reference needed
private static class Node<T> {
final T value;
final Node<T> next;
Node(T value, Node<T> next) { this.value = value; this.next = next; }
}
private Node<T> top;
private int size;
void push(T value) { top = new Node<>(value, top); size++; }
T pop() {
if (top == null) throw new IllegalStateException("empty stack");
T v = top.value;
top = top.next;
size--;
return v;
}
public static void main(String[] args) {
LinkedStack<String> history = new LinkedStack<>();
history.push("/home");
history.push("/java");
history.push("/java/static-nested-class");
System.out.println("size = " + history.size);
while (history.size > 0) System.out.println("back to " + history.pop());
}
}
size = 3 back to /java/static-nested-class back to /java back to /home
Because Node is static, each node stores only its value and next pointer, not an extra reference to the stack object, saving memory for every element.
5. Use 3: Lazy, Thread-Safe Singleton (Holder Idiom)
A nested class is loaded and initialised only when it is first used. The JVM guarantees that class initialisation is thread-safe, which gives lazy singletons without any locking:
public class HolderSingleton {
static class Config {
private Config() { System.out.println("Config created (lazily, thread-safe)"); }
// The holder class is loaded only when getInstance() is first called
private static class Holder {
static final Config INSTANCE = new Config();
}
static Config getInstance() { return Holder.INSTANCE; }
static void ping() { System.out.println("Config.ping() - instance not created yet"); }
}
public static void main(String[] args) {
Config.ping();
Config a = Config.getInstance();
Config b = Config.getInstance();
System.out.println("same instance: " + (a == b));
}
}
Config.ping() - instance not created yet Config created (lazily, thread-safe) same instance: true
6. Static Nested Class vs Inner Class
| Aspect | Static nested class | Inner (non-static) class |
|---|---|---|
| Keyword | static | None |
| Instantiation | new Outer.Nested() | outer.new Inner() |
| Outer instance reference | None | Hidden reference in every object |
| Access to outer instance members | Through an explicit reference only | Direct |
| Access to outer static members | Direct | Direct |
| Memory-leak risk | Low | Can keep the outer object alive |
Effective Java's advice: "favour static member classes over non-static" unless each instance truly needs its enclosing instance.
7. Notes
- The class file is
Outer$Nested.class; with reflection, useClass.forName("pkg.Outer$Nested"). - Static nested classes can be imported:
import pkg.Outer.Nested;. - Nested interfaces, enums and records are always implicitly static.
- A static nested class with a
mainmethod can be run withjava Outer$Nested(quote the$in Unix shells).
8. Summary
- A static nested class is declared with
staticinside another class and needs no outer instance. - It accesses outer static members directly and instance members only through a reference.
- Common uses: builders, private node/entry classes and the lazy holder singleton.
- Prefer it over an inner class whenever the outer instance is not needed.
Related Tutorials
Frequently Asked Questions (FAQ)
Q1. What is a static nested class in Java?
A class declared with static inside another class. It is associated with the outer class rather than an outer object.
Q2. Is a static nested class the same as a static inner class?
"Static inner class" is a common informal name, but by the Java specification inner classes are non-static. The correct term is static nested class.
Q3. How do I create an object of a static nested class?
Outer.Nested obj = new Outer.Nested();, with no outer object.
Q4. Can a static nested class access instance variables of the outer class?
Not directly. It needs a reference to an outer object, because it has no implicit one.
Q5. Can a static nested class access private static members of the outer class?
Yes, directly.
Q6. Can a static nested class have non-static members?
Yes. It can have instance fields and methods like any class; "static" only describes its relationship to the outer class.
Q7. Can a top-level class be static?
No. Only member classes can be declared static.
Q8. Why use a static nested class?
To group a helper class with the class that uses it, control its visibility, and avoid the memory and coupling cost of an outer reference.
Q9. Can a static nested class be private?
Yes. A private static nested class is visible only inside the outer class, which is ideal for implementation details.
Q10. Is a static nested class loaded with the outer class?
No. It is loaded and initialised separately, when first used, which the holder singleton idiom relies on.
Q11. What are examples of static nested classes in the JDK?
HashMap.Node, AbstractMap.SimpleEntry, Character.UnicodeBlock and HttpClient-related builders and nested types.
Q12. What is the holder idiom?
A lazy, thread-safe singleton where the instance is stored in a static field of a private static nested class, created when the nested class is first accessed.
Q13. Why is the builder usually a static nested class?
The builder must exist before the object it builds, so it cannot depend on an outer instance, and nesting lets it call the outer class's private constructor.
Q14. Can a static nested class extend its outer class?
Yes. This is sometimes used in sealed hierarchies where subtypes are nested inside the parent.
Q15. Can a static nested class be instantiated multiple times?
Yes. "static" does not mean single instance; you can create as many objects as you like.
Q16. Can a static nested class have a main method?
Yes, and it can be run with java Outer$Nested.
Q17. Do nested records need the static keyword?
No. Nested records, enums and interfaces are implicitly static.
Q18. How do I refer to a static nested class from another class?
Use Outer.Nested, or import it with import pkg.Outer.Nested; and use the simple name.
Q19. Can a static nested class be generic?
Yes, but it cannot use the outer class's type parameters, because it has no outer instance; it declares its own, as Node<T> does.
Q20. Is a static nested class serializable?
If it implements Serializable, yes, and it serializes cleanly because it has no hidden outer reference.