Memra

Classes, constructors, static & initialization order

Constructor overloading, this, final fields, and the exact order fields and blocks initialise.

Constructors and this

A constructor has the class name, no return type, and runs once when an object is created with new. You can overload constructors (same name, different parameter lists) and reuse one from another with this(...):

class Point {
    final int x;            // blank final: must be set by every constructor
    final int y;

    Point(int x, int y) {   // primary constructor
        this.x = x;         // 'this' disambiguates field from parameter
        this.y = y;
    }
    Point() {               // no-arg overload delegates to the primary
        this(0, 0);         // MUST be the first statement
    }
}

this.x = x is needed because the parameter x *shadows* the field x; this reaches the field. this(0, 0) is a constructor call and, if present, must be the first statement.

final fields

A final field can be assigned exactly once. A blank final is declared without a value and *must* be set by the time every constructor finishes — the compiler enforces it. Once set it cannot change, which is how you make immutable value objects.

static: per-class, not per-object

A static field belongs to the class, shared by all instances; a non-static (instance) field gets its own copy per object. A static method has no this and can be called on the class itself (Math.max(...)).

class Counter {
    static int created = 0;   // one shared slot for the whole class
    int id;                   // one per instance
    Counter() { id = ++created; }
}

Initialization order (the classic exam trace)

This is *the* MED-tagged trace question. The exact order when the class is first used and then instantiated:

  1. Static fields and static initializer blocks, in source order — once, the first time the class is loaded.
  2. Then, on each new:
  3. a. Instance fields and instance initializer blocks, in source order.
  4. b. The constructor body.

Worked trace:

class Demo {
    static int s = log("static field");
    static { log("static block"); }
    int i = log("instance field");
    { log("instance block"); }
    Demo() { log("constructor"); }
    static int log(String m) { System.out.println(m); return 0; }
}
// new Demo(); new Demo();  prints:
// static field        <- once, at class load
// static block        <- once, at class load
// instance field      <- first new
// instance block
// constructor
// instance field      <- second new (statics do NOT repeat)
// instance block
// constructor

The takeaways the exam tests: statics run once, before any instance work, and within each group declarations and blocks run top-to-bottom in source order — not constructor-first.

Default and no-arg constructors

If you write no constructor, the compiler supplies a public no-arg default. The moment you write *any* constructor, that default disappears — a later new Point() then fails to compile unless you add a no-arg overload yourself.

NORMAL ~/memra/learn/comp-308/classes-constructors-static-init-order utf-8 LF