Object Creation

Every Java object begins life through the new keyword or an equivalent mechanism, which allocates storage, runs constructors top-down through the class hierarchy, and hands back a reference to the finished object.

Object creation in Java is a well-defined sequence: memory is allocated for the new object's fields, those fields get their default values, constructors run from the topmost superclass down to the actual class (running field initializers and instance initializer blocks along the way), and finally a reference to the fully-constructed object is returned to the caller. Understanding this sequence explains a surprising amount of Java's behavior around initialization order and constructor chaining.

The new Keyword

new is the primary way to create an object: it allocates storage sized for the class's instance fields, initializes those fields to their type's default value (0, false, null, etc.), then invokes the matching constructor, which sets up the object's actual initial state. The expression new ClassName(args) evaluates to a reference to the newly created object.

class Point {
    int x, y;
    Point(int x, int y) { this.x = x; this.y = y; }
}

Point p = new Point(3, 4);
// 1. storage allocated for a Point (x=0, y=0 defaults)
// 2. Point(3, 4) constructor runs, setting x=3, y=4
// 3. reference to the object assigned to p

Constructors

A constructor has the same name as its class and no return type (not even void). If a class declares no constructor at all, the compiler supplies a no-argument default constructor that just calls super(). Once you declare any constructor yourself, the compiler no longer provides that default — you must supply a no-arg constructor explicitly if you still want one.

class Empty { } // compiler generates: Empty() { super(); }

class HasCtor {
    HasCtor(int x) { }
    // no default() constructor is generated here - HasCtor() no longer exists
}
// new HasCtor(); // COMPILE ERROR - no matching constructor

Constructor Chaining: this() and super()

A constructor can delegate to another constructor of the same class with this(...), or to its superclass's constructor with super(...). If neither is written explicitly as the first statement, the compiler inserts an implicit super() call to the superclass's no-arg constructor. At most one of this(...) or super(...) may appear, and it must be the very first statement.

class Vehicle {
    String type;
    Vehicle(String type) { this.type = type; }
}

class Car extends Vehicle {
    int doors;
    Car(int doors) {
        this("car", doors); // delegate to the other Car constructor
    }
    Car(String type, int doors) {
        super(type); // must call Vehicle's constructor explicitly - no no-arg Vehicle() exists
        this.doors = doors;
    }
}

Initialization Order

For any single new expression, initialization proceeds in this order: (1) fields get default values, (2) the superclass's constructor runs completely first (recursively following the same rules), (3) instance field initializers and instance initializer blocks run in the order they appear in the source, (4) the rest of this class's constructor body runs.

Superclass constructor runs first, then field initializers/instance blocks in source order, then the constructor body's remaining statements.

class A {
    A() { System.out.println("A ctor"); }
}
class B extends A {
    int x = init();
    { System.out.println("B instance block"); }
    B() {
        System.out.println("B ctor");
    }
    static int init() {
        System.out.println("B field init");
        return 1;
    }
}
new B();
// Output:
// A ctor
// B field init
// B instance block
// B ctor

References Returned by new

new produces a reference value, not the object itself — the variable holding the result of new stores a reference (conceptually, an address/handle the JVM manages) to the object's memory, not the object's bytes inline. Assigning that reference to another variable copies the reference, not the object; both variables then point to the same single object.

Point p1 = new Point(1, 2);
Point p2 = p1;   // p2 now references the SAME object as p1
p2.x = 99;
System.out.println(p1.x); // 99 - p1 and p2 refer to the identical object

Object Identity vs Equality

Each new call, even with identical arguments, produces a distinct object with its own identity. == on reference types compares identity (do these two references point to the same object?), which is different from .equals(), whose behavior depends entirely on the class's own implementation.

Point a = new Point(1, 2);
Point b = new Point(1, 2);
System.out.println(a == b);        // false - two distinct objects
System.out.println(a.equals(b));   // depends on Point's equals() override; Object's default equals() also returns false here

Object Header Concept (Allocation)

Conceptually, when the JVM allocates an object it reserves memory for the object's declared instance fields plus some implementation-managed bookkeeping (often loosely called an "object header" — used for things like the object's runtime type and locking state). The exact layout, size, and content of this bookkeeping is JVM-implementation-dependent and not specified by the Java Language Specification — Java code never directly reads or manipulates it.

A typical HotSpot JVM may lay out an object as a small header followed by its fields, but this is an implementation detail, not a language guarantee — different JVMs are free to organize object memory differently.

Arrays as Objects

Arrays in Java are objects too, created with new (or an array initializer), living on the heap, and accessed through references just like any other object. An array's length is a public final field (not a method), and every array has a runtime type that includes its element type and dimensionality.

int[] nums = new int[5];       // array object, elements default to 0
String[] names = {"a", "b"};   // array initializer shorthand, still an object

System.out.println(nums.length);          // 5, a field access, not a method call
System.out.println(nums.getClass());      // class [I  (JVM's internal name for int[])
System.out.println(nums instanceof Object); // true - arrays ARE objects

Other Ways Objects Get Created

Beyond an explicit new expression, objects also come into being through: reflective construction (Class.newInstance()-style APIs, Constructor.newInstance()), deserialization (which reconstructs an object's state without calling a normal constructor), Object.clone() (which copies an existing object's state), and autoboxing of primitives into wrapper objects (though small boxed integer values may come from a cached pool rather than a fresh allocation, an implementation detail, not a language guarantee).

Integer a = 100; // autoboxed - may reuse a cached Integer instance
Integer b = 100;
System.out.println(a == b); // true, typically, for small cached values (JVM-dependent range)

Integer c = 200;
Integer d = 200;
System.out.println(c == d); // false, typically, outside the cached range - always use .equals() to compare

Practical Usage

Understanding constructor chaining and initialization order matters most when writing class hierarchies: putting expensive or side-effecting logic in field initializers that run before the subclass constructor body executes, or calling an overridable method from a superclass constructor (which can run before the subclass has finished its own initialization), are both classic sources of subtle bugs.

Edge Cases

Calling an overridable instance method from a constructor is dangerous: if a subclass overrides that method, the override runs during the superclass constructor, potentially before the subclass's own fields have been initialized — reading them at that point sees their default values, not what the subclass constructor would eventually set.

This is why 'don't call overridable methods from a constructor' is a well-known best practice.

class Base {
    Base() { report(); } // calls overridable method during construction
    void report() { System.out.println("Base"); }
}
class Derived extends Base {
    String name = "Derived"; // not yet assigned when Base() runs
    @Override void report() { System.out.println("name=" + name); }
}
new Derived();
// Prints: name=null  (Derived's field initializer hasn't run yet when Base's constructor calls report())

Mental Model

Picture object construction as building from the ground up: the foundation (superclass state) must be fully poured before the next floor (this class's fields and constructor body) is built on top of it. new is the whole construction project from blueprint (the class) to a finished, occupiable building (the object) whose address (reference) you're handed at the end.

Quick Reference

new ClassName(args)   // allocate + run constructor chain, returns a reference

Construction order per object:
  1. fields default-initialized (0/false/null)
  2. superclass constructor runs fully (recursively)
  3. field initializers / instance blocks, in source order
  4. rest of this constructor's body

this(...) / super(...) - must be first statement, at most one of them

Key Takeaways

new allocates storage, runs the constructor chain from superclass down to subclass, and returns a reference to the new object.

If a class declares no constructor, the compiler supplies a no-arg default one; declaring any constructor removes that default.

Field initializers and instance blocks run in source order, after the superclass constructor but before the rest of this class's constructor body.

Every new call creates a distinct object with its own identity, even with identical arguments - == checks identity, .equals() checks whatever the class defines as equality.

Arrays are objects too, created via new or an initializer, with a public final length field and a runtime element type.

Never rely on calling an overridable method from a constructor - it can run before a subclass's own field initializers have executed.

class Base { Base() { init(); } // calls overridable method void init() { } } class Base { Base() { doInit(); } // private/final - not overridable private void doInit() { } }

Calling an overridable method from a constructor risks running subclass logic before the subclass's own fields are initialized. Make constructor-invoked methods private or final.

Point a = new Point(1, 2); Point b = new Point(1, 2); if (a == b) { /* assumes same values means same reference */ } if (a.equals(b)) { /* correct - compares logical equality via equals() */ }

Each new call produces a distinct object; == on references checks identity, not field equality. Use equals() (with a correct override) for value comparison.

class Config { Config(int a) { } } // later, elsewhere: new Config(); // assumed a default constructor still exists class Config { Config() { this(0); } // explicit no-arg constructor, if still needed Config(int a) { } }

Declaring any constructor removes the compiler-generated no-arg default - you must add one explicitly if callers still need to construct with no arguments.

What exactly does the expression new Point(3, 4) produce as its value?

A reference to a newly allocated Point object whose constructor has already run to completion - the expression's value is that reference, not the object's raw memory.

In a subclass constructor with no explicit this(...) or super(...) call, what does the compiler insert, and where?

It inserts an implicit super() call (invoking the superclass's no-arg constructor) as the very first statement of the constructor.

What is the initialization order for field initializers, instance blocks, and constructor body statements within one class?

The superclass constructor runs to completion first; then this class's field initializers and instance initializer blocks run in the order they appear in the source; then the remaining statements of this class's own constructor body run.

Why is calling an overridable method from a constructor considered risky?

If a subclass overrides that method, the override executes during the superclass's constructor call - potentially before the subclass's own field initializers have run - so the override may observe default (zero/null) values instead of the subclass's intended initial state.

Are arrays objects in Java? What evidence supports that?

Yes - arrays are created with new (or an initializer), live on the heap, are accessed through references, have a runtime class (e.g. int[].class), and arr instanceof Object is true.

If a class declares a constructor that takes an int parameter and no other constructor, can you still call new MyClass() with no arguments?

No, not unless you explicitly declare a no-argument constructor yourself - declaring any constructor suppresses the compiler-generated default no-arg constructor.

Why does a == b return false for two Point objects constructed with the same coordinate values (assuming Point doesn't override equals)?

== on reference types compares identity - whether both references point to the very same object in memory. Two separate new calls always produce two distinct objects, regardless of whether their field values happen to match.

What is printed, and why?

Prints "A" then "B, x=5". The implicit super() call runs A's constructor first (printing A), then B's field initializer sets x=5, then B's constructor body runs (printing B, x=5).

Write a class Employee with two constructors: one taking (String name), which delegates via this(...) to a second constructor taking (String name, double salary) that defaults salary to 0.0.

class Employee { String name; double salary; Employee(String name) { this(name, 0.0); } Employee(String name, double salary) { this.name = name; this.salary = salary; } } new Employee("Ann") delegates to Employee("Ann", 0.0), setting name="Ann" and salary=0.0. this(...) must be the first statement in the delegating constructor.

What is printed?

99. Arrays are objects, so arr2 = arr1 copies the reference, not the array's contents - both variables refer to the same underlying array object, so mutating through arr2 is visible through arr1.

Write a class Base with a final method describe() called from its constructor, and a subclass Derived that cannot override it, demonstrating the safe alternative to calling an overridable method from a constructor.

class Base { Base() { describe(); } final void describe() { System.out.println("I am a Base"); } } class Derived extends Base { // cannot override describe() - it's final } new Derived(); // prints "I am a Base" safely, no risk of reading uninitialized subclass state

Because describe() is final, Derived cannot override it, so Base's constructor is guaranteed to run the exact same describe() logic regardless of subclass - eliminating the uninitialized-subclass-state hazard.

class A {
    A() { System.out.println("A"); }
}
class B extends A {
    int x = 5;
    B() {
        System.out.println("B, x=" + x);
    }
}
new B();
int[] arr1 = new int[3];
int[] arr2 = arr1;
arr2[0] = 99;
System.out.println(arr1[0]);