Inheritancesenior8+ years

`class Base { Base() { init(); } void init() {} }` and `class Derived extends Base { final List<String> items = new ArrayList<>(); @Override void init() { items.add("x"); } }` — constructing a `Derived` throws `NullPointerException` inside `init()`, on a field marked `final` that's initialised right there at its declaration. How, precisely, does an object's class pointer already being `Derived` from the moment of allocation explain this, and why doesn't `final` help?

new Derived() allocates the object with its class pointer set to Derived immediately — before any constructor has run a single line — and every virtual call the JVM makes against that object, from that instant on, dispatches through Derived's vtable, not Base's. Base's constructor calling init() is an ordinary virtual call (invokevirtual), and because the object's class pointer already says Derived, that call lands on Derived.init() — even though Base's constructor is still running and Derived's own constructor, including the field initialiser for items, hasn't executed yet. items is final, but final only means "assigned exactly once"; it says nothing about when that single assignment happens relative to a virtual call landing on code that reads it, so the override runs against a null items regardless of the final keyword.

The lesson behind it →
More on Inheritance