Construction & this
Once you understand that objects have identity and state, the next question is how they are born safely. Construction is where an object moves from a description into a valid runtime instance, and this is the pointer that lets the object refer to itself during that process.
Blueprint vs. Instance Allocation
A class is the blueprint. It defines field order, type expectations, constructor signatures, and method dispatch metadata. It does not hold per-object state by itself.
An object is the allocated instance. When new Movie(...) runs, the runtime reserves space for the object header, field slots, and hidden metadata such as a class pointer or vtable pointer. The returned variable does not contain the full object; it contains an address-like reference to that heap allocation.
For primitive fields, default initialization writes type-specific zero values: 0, 0.0, false, or equivalent. For reference fields, default initialization writes null, because the runtime has no nested object address until one is explicitly assigned.
Constructor Lifecycle
Constructors are controlled entry points into valid object state.
Default or no-arg constructors create a valid instance without caller-supplied state. If the class does not define any constructor, many languages synthesize one. If fields are not explicitly assigned, default values remain in their slots.
Parameterized constructors bind runtime arguments into instance fields before exposing the reference. This matters because it prevents client code from observing a partially initialized object.
Copy constructors define how identity and ownership should move from one object to another. A shallow copy duplicates field values exactly, including nested reference addresses. A deep copy recursively allocates new nested objects so mutation through the copy cannot corrupt the original.
Private constructors move allocation authority away from external callers. This is useful when you want a static gatekeeper such as getInstance() to decide when the object may be allocated and which reference all callers receive.
The Current Object Pointer
Inside a non-static method, this is the implicit reference to the current object. It is passed into instance method calls by the runtime, even when it is not visible in the method signature.
this resolves collisions between parameter names and field names:
class Movie {
private String title;
Movie(String title) {
this.title = title;
}
}
It also enables constructor chaining and fluent APIs. Returning this returns the same live receiver object, allowing method chains like builder.setName("x").setRuntime(120).
Static methods do not have this, because they bind to the class definition rather than a particular heap instance.
Lab 2.1: The Reference Memory Leak
This lab starts with a Movie object that owns a mutable nested Cast structure. The initial code aliases copyMovie to originalMovie, so both variables point to the same heap object. Run the engine first to see the corruption, then add a deep-copy constructor that duplicates the nested cast member array.
Exercise 2.1: Copy Constructor Basics
Pattern-based checker only — it inspects code shape and state flow, but it does not compile Java.
Replace aliasing with a copy constructor so the new object gets its own identity.
- Edit the code, then run the inspector.
Lab 2.2: Constructing the Singleton Guard
The unsafe version of ConfigRegistry can allocate two objects when two threads observe instance == null at the same time. Secure it by hiding the constructor and implementing double-checked locking with a volatile static reference.
Exercise 2.2: Singleton Basics
Pattern-based checker only — it inspects code shape and state flow, but it does not compile Java.
Hide raw construction and make every call return the same shared instance.
- Edit the code, then run the inspector.