Object Creation and Initialisation
new allocates memory on the heap, zero-initialises fields, runs field initialisers in declaration order, then runs the constructor body after any super(...) call. The full initialisation sequence:
- Superclass fields are zero-initialised, then initialisers run, then the superclass constructor body executes. This continues up the chain to
Object. - Then this class’s fields are zero-initialised, initialisers run, then the constructor body executes.
This ordering ensures invariants are always maintained — a superclass’s constructor never sees subclass fields (they are still zero at that point).
Worked Example
class Grandparent {
int x = 10;
Grandparent() {
print();
}
void print() { System.out.println("Grandparent.x = " + x); }
}
class Parent extends Grandparent {
int y = 20;
Parent() {
print();
}
@Override void print() { System.out.println("Parent: x=" + x + ", y=" + y); }
}
class Child extends Parent {
int z = 30;
Child() {
super();
print();
z = 40;
}
@Override void print() { System.out.println("Child: x=" + x + ", y=" + y + ", z=" + z); }
}
public class Test {
public static void main(String[] args) {
new Child();
}
}
When new Child() executes, the sequence is:
- Memory for
Childallocated on the heap; all fields zeroed (x=0,y=0,z=0) Child()constructor body begins with an implicitsuper()callParent()constructor body begins with an implicitsuper()callGrandparent()constructor runs:xinitialiser setsx = 10- Constructor body calls
this.print()— butthisis aChild(dynamic dispatch), soChild.print()runs, printingx=10, y=0, z=0
Parent()constructor continues:yinitialiser setsy = 20- Constructor body calls
this.print()— again dispatches toChild.print(), printingx=10, y=20, z=0
Child()constructor continues:zinitialiser setsz = 30- Constructor body calls
this.print(), printingx=10, y=20, z=30 - Then
z = 40executes
This demonstrates why calling overridable methods from constructors is dangerous — z was 0 when the grandparent’s constructor ran because it hadn’t been initialised yet.
The Stages of new
| Stage | What Happens |
|---|---|
| 1. Allocation | Memory for the new object is allocated on the heap |
| 2. Zeroing | All fields are set to default values (0, false, null, \u0000) |
3. super() | The superclass constructor is invoked, recursively |
| 4. Instance initialisers | Field initialisers and instance initialiser blocks run in declaration order |
| 5. Constructor body | The remainder of the constructor’s own code executes |
Initialiser Blocks
Instance initialisers run before the constructor body. They are declared as a bare { ... } block directly inside a class body:
class Example {
int a;
{
a = 5;
System.out.println("Instance initialiser: a = " + a);
}
Example() {
System.out.println("Constructor: a = " + a);
}
}
Static initialisers run once when the class is first loaded by the JVM — before any instance is created and before any static method or field is accessed:
class Example {
static int count;
static {
count = 42;
System.out.println("Static initialiser: count = " + count);
}
}
Static initialisers run in declaration order and are useful for initialising static fields that cannot be expressed in a single expression.
Object Lifetime
An object exists from construction until it becomes unreachable — meaning no live reference chain from a GC root reaches it. At that point the object becomes eligible for collection.
An object is not destroyed immediately when it becomes unreachable. Garbage collection happens at the JVM’s discretion — the collector may run minutes later, or never, depending on memory pressure and JVM implementation. You cannot force the GC to run; System.gc() is merely a suggestion.
GC roots include:
- Local variables on active stack frames
- Static fields of loaded classes
- Active thread references
- JNI (native interface) references
- Objects kept alive by finalisers or reference queues
An object that is unreachable but whose finalize() method has not yet been called may briefly become reachable again if finalize() stores the this reference somewhere — this is called object resurrection and is one reason finalize() is deprecated.