What happens between writing new and having a usable object, and in what order do the constructors run in a hierarchy?
The runtime allocates memory for the object first, then initialises it. The sequence is: memory is allocated, the fields get their default values, the instance field initialisers and the initialiser blocks run, the constructor of the superclass runs, and finally the constructor of the subclass runs. Only after all of that does the reference become usable by the caller.
public class Main {
public static void main(String[] args) {
Laptop laptop = new Laptop("pro", 16);
System.out.println(laptop.describe());
}
}
class Device {
protected final String model;
Device(String model) {
this.model = model;
System.out.println("device ready: " + model);
}
}
class Laptop extends Device {
private final int ram;
Laptop(String model, int ram) {
super(model);
this.ram = ram;
System.out.println("laptop ready: " + model + " with " + ram + "GB");
}
String describe() { return model + "/" + ram; }
}The output confirms the order. The device constructor runs first and prints that the device is ready, and only afterwards does the laptop constructor run and print its own message. That ordering is not a style choice; it is forced, because the subclass cannot use inherited state until the superclass has finished initialising it.
Two implications are worth drawing out. First, a subclass constructor must call the super constructor before doing anything else, and if the parent has no no-argument constructor you have to say which one you mean. Second, an overridden method called from a superclass constructor runs the subclass version, before the subclass fields are initialised, which is a classic source of surprising behaviour.
The final stage of the lifecycle is reclamation. When an object becomes unreachable the collector reclaims it, but that is only about memory. Anything else the object holds has to be released explicitly, and the try-with-resources pattern is the safe way to do that.