skip to content

How does `this` relate to `super`, and is the `this` seen inside an inherited method the subclass object or the superclass part?

level: seniorimportance: should knowfreq 45%

answer

  1. one object, two keywords
  2. this = whole runtime subclass instance
  3. super = parent member version, non-virtual, not a separate object
  4. inherited method's this dispatches to override
  5. constructor calling overridable -> override runs before subfields init

basics

~20 s

There is only one object. this always refers to that whole object (the actual runtime subclass instance), even inside an inherited superclass method. super is not a different object — it just accesses the parent's version of members on the same this.

solid answer

~50 s

When a subclass extends a superclass, instantiating the subclass creates a single object that contains both the inherited and the new state. `this` always refers to that one whole object, identified by its actual runtime type. So inside an inherited method declared in the superclass, `this` is still the subclass instance — which is why a virtual call like `this.foo()` (or the implicit `foo()`) dispatches to the subclass's override, even when the call originates in superclass code. `super` is not a reference to a separate object; it is a keyword that tells the compiler to resolve a member against the *superclass* declaration, bypassing dynamic dispatch for that one call (`super.foo()` runs the parent's version non-virtually). A common gotcha follows: calling an overridable method from a superclass constructor invokes the subclass override via `this`'s dynamic type before the subclass's fields are initialized, exposing default values. `this == super` conceptually (same object); they differ only in which member version is selected.

code

java · 12 lines
java
class Animal {
    void describe() { System.out.println("I am " + name()); } // this.name()
    String name() { return "animal"; }
}
class Dog extends Animal {
    @Override String name() { return "dog"; }
    void both() {
        System.out.println(name());        // dog  (this -> override)
        System.out.println(super.name());  // animal (parent version)
    }
}
// new Dog().describe();  -> "I am dog"

go deeper

for a junior

Knows this is the current object and super reaches the parent's members; may not yet grasp dispatch on the runtime type.

for a middle

Understands that an inherited method's this is the subclass and that super.m() calls the parent version, but may miss the construction-order trap.

for a senior

Explains one-object identity, virtual dispatch on this, super as non-virtual member resolution, and the overridable-method-in-constructor pitfall, including that casts don't change dispatch.

for a principal

Reasons about these semantics when designing extensible base classes (template-method safety, final/private hooks), documents construction contracts, and avoids self-use of overridable methods in library superclasses.

## One object, two keywords Inheritance does not create two objects. When you write `new Dog()` and `Dog extends Animal`, the JVM allocates **one** object whose memory holds the `Animal` fields plus the `Dog` fields. There is a single identity. - **`this`** refers to that one whole object, and its dynamic (runtime) type is the *actual* class you instantiated (`Dog`). - **`super`** is **not** a reference to a different object. It is a compiler directive meaning "resolve this member against my **superclass's** declaration." `super.x` reads the parent's field declaration; `super.m()` calls the parent's method **non-virtually** (without dynamic dispatch). So `this` and `super`, where they refer to state, point at the *same* object; they differ only in **which inherited version of a member** the compiler picks. ## `this` inside an inherited method is the subclass Because Java instance methods are **virtual** (dynamically dispatched on the runtime type of the receiver), the `this` inside a superclass-declared method is the runtime subclass object. Consider: ```java class Animal { void describe() { System.out.println("I am " + name()); } String name() { return "animal"; } } class Dog extends Animal { @Override String name() { return "dog"; } } new Dog().describe(); // prints "I am dog" ``` `describe()` is declared only in `Animal`, but the implicit `this.name()` it calls dispatches on `this`'s runtime type `Dog`, so the override runs. This is the heart of polymorphism: superclass code automatically calls subclass behavior through `this`. ## `super` bypasses dispatch for one call Inside `Dog`, `super.name()` would call `Animal.name()` directly, *not* `Dog.name()`, even though `this` is a `Dog`. `super` is the only standard way to invoke an overridden parent implementation; you cannot get the same effect with a cast (`((Animal) this).name()` still dispatches to `Dog.name()` because casting changes the static type but not the dynamic dispatch target). ## The constructor gotcha Because `this`'s dynamic type is fixed from allocation, calling an **overridable** method from a superclass constructor dispatches to the subclass override *before the subclass constructor body has run*: ```java class Base { Base() { init(); } // calls the overridable method void init() {} } class Sub extends Base { private String val = "set"; @Override void init() { System.out.println(val); } // prints null! } new Sub(); ``` Construction order is: `Base()` runs first (calling `init()`, which dynamically dispatches to `Sub.init()`), but `Sub`'s field initializer (`val = "set"`) has **not** executed yet, so `val` is still `null`. The lesson: never call overridable methods from a constructor. ## `super(...)` and `this(...)` in constructors There are also the constructor-invocation forms: `super(args)` calls a parent constructor, `this(args)` chains to another constructor of the same class; each must be the first statement. These reuse the keywords but are a distinct mechanism (constructor chaining) from member access. ## Identity check `this == this` is trivially true; there is no `super` object to compare, reinforcing that `super` is a resolution mechanism, not an object. Reflexively, the object's `getClass()` inside an inherited method returns the subclass, confirming `this` is the subclass instance. ## Takeaways - One object; `this` = the whole runtime subclass instance. - `super` selects the parent's member version (non-virtual), not a separate object. - Virtual dispatch on `this` makes superclass code invoke subclass overrides — both the power (polymorphism) and the trap (constructor calling overridable methods).

  • Can you reach the superclass method via a cast instead of `super`?
    No. `((Animal) this).name()` still dynamically dispatches to the override because the cast changes only the static type, not the runtime dispatch target. Only `super.name()` invokes the parent's implementation.
  • Why does calling an overridable method from a constructor print null/default field values?
    `this`'s dynamic type is the subclass from allocation, so the call dispatches to the subclass override before the subclass's field initializers and constructor body have run, leaving those fields at defaults.

this and super are like a person's full self versus their inherited surname: there's one person (this), and super just says 'use the family's traditional way of doing this one thing' instead of your own.

saying these in an interview costs you the question

  • Treating `super` as a reference to a separate parent object.
  • Saying `this` inside an inherited method is the superclass 'part' rather than the whole subclass object.
  • Believing a cast to the parent type changes which overridden method runs.
  • Calling overridable methods from constructors expecting subclass fields to be initialized.

context