# Inheritance and Polymorphism

## 1. `extends` and Single Inheritance

A class can extend exactly one superclass (Java has no multiple class inheritance, unlike C++). Every class that doesn't explicitly extend anything implicitly extends `Object`.

```java
class Animal {
    String name;
    Animal(String name) { this.name = name; }
    String speak() { return name + " makes a sound"; }
}

class Dog extends Animal {
    Dog(String name) { super(name); } // must call a superclass constructor first
    @Override
    String speak() { return name + " barks"; }
}

Animal a = new Dog("Rex");
System.out.println(a.speak()); // "Rex barks" — the OVERRIDE runs, even though `a` is typed Animal
```

## 2. `super` — Calling Up the Chain

`super(...)` calls a superclass constructor and must be the first statement in a subclass constructor (if you don't write it, the compiler inserts an implicit `super()` — the no-arg version — which fails to compile if the superclass has no no-arg constructor). `super.method()` calls the superclass's version of an overridden method explicitly.

```java
class Cat extends Animal {
    Cat(String name) { super(name); }
    @Override
    String speak() {
        return super.speak() + ", specifically a meow"; // extends rather than replaces the parent behavior
    }
}
```

## 3. Method Overriding Rules

An override must have the same signature (name + parameter types), a covariant or identical return type, and cannot narrow the declared checked exceptions or reduce visibility. `@Override` is optional but strongly recommended — it makes the compiler verify you actually matched a superclass method, catching typos that would otherwise silently create an unrelated overload instead of an override.

```java
class Shape {
    Shape self() { return this; }
    void resize(int factor) throws Exception { }
}

class Circle extends Shape {
    @Override
    Circle self() { return this; }         // covariant return type: Circle is-a Shape — allowed
    @Override
    void resize(int factor) { }              // narrowing (dropping) a checked exception is allowed
    // void resize(int factor) throws IOException {} // ERROR if not declared by the superclass — cannot WIDEN
}
```

## 4. Fields Are Not Polymorphic — Only Methods Are

This is one of the most important and most surprising rules in the language: field access is resolved by the **declared (compile-time) type** of the reference, not the runtime type of the object. Overriding only applies to methods.

```java
class Base { String label = "base"; }
class Derived extends Base { String label = "derived"; }

Base b = new Derived();
System.out.println(b.label);            // "base" — field access uses the DECLARED type
System.out.println(((Derived) b).label); // "derived" — only visible after an explicit cast
```

## 5. Abstract Classes

An `abstract` class cannot be instantiated and may declare methods with no body (`abstract` methods) that subclasses are forced to implement.

```java
abstract class Shape {
    abstract double area();                    // no body — subclasses MUST implement
    String describe() { return "area=" + area(); } // concrete method, can call the abstract one
}

class Square extends Shape {
    double side;
    Square(double side) { this.side = side; }
    @Override
    double area() { return side * side; }
}
```

## 6. Interfaces

An interface defines a contract; a class can implement any number of interfaces (this is Java's answer to the lack of multiple class inheritance). Since Java 8, interfaces may also provide `default` method bodies and `static` methods.

```java
interface Movable {
    void move(int dx, int dy);

    default String describeMovement() { // default method — concrete, inherited unless overridden
        return "can move";
    }
}

interface Drawable {
    void draw();
}

class Sprite implements Movable, Drawable {
    public void move(int dx, int dy) { /* ... */ }
    public void draw() { /* ... */ }
}
```

| | Abstract class | Interface |
|---|---|---|
| Instance fields | yes | only `public static final` constants |
| Constructors | yes | no |
| Multiple inheritance | no (single `extends`) | yes (multiple `implements`) |
| Method bodies | yes (mix of abstract + concrete) | yes, via `default`/`static` (Java 8+) |
| When to use | shared state + a strong "is-a" hierarchy | a capability/contract many unrelated classes can satisfy |

## 7. `Object`'s Methods: `equals`, `hashCode`, `toString`

Every class inherits `equals`, `hashCode`, and `toString` from `Object`. The defaults are reference-identity based and rarely what you want for value-like classes.

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

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (!(o instanceof Point p)) return false; // pattern-matching instanceof, Java 16+
        return x == p.x && y == p.y;
    }

    @Override
    public int hashCode() {
        return java.util.Objects.hash(x, y);
    }

    @Override
    public String toString() {
        return "Point(" + x + ", " + y + ")";
    }
}
```

![Animal.speak and Dog.speak both occupy slot 3 of their respective method tables; invokevirtual resolves through the runtime object's actual table, landing on Dog's override even when the reference is declared as Animal](diagrams/01-dynamic-dispatch.svg)

## Under the Hood

**Dynamic dispatch is table-driven, not a linear name search at call time.** Every class HotSpot loads has an associated **virtual method table** (informally, a "vtable," though HotSpot's actual internal structures are more elaborate — `Klass::vtable()`): a flat array where each slot corresponds to one overridable method, and overriding a method in a subclass simply overwrites that same slot with a pointer to the subclass's implementation rather than adding a new slot. When you call `a.speak()` on a reference declared `Animal`, the compiler emits an `invokevirtual` instruction identifying *which slot* `speak` lives in (resolved once, at compile/link time, from the static type). At runtime, the JVM looks at the object's *actual* class pointer (from the object header, see the OOP Fundamentals topic), follows it to that class's vtable, and reads out whatever is currently in that slot — which is `Dog`'s override if the object is really a `Dog`. The slot index is fixed by the static type hierarchy; only the *contents* of the slot vary by runtime type. This is why overriding doesn't require walking a name-based lookup chain at every call — it's an array index.

**Interface method calls use a separate mechanism: itables (or a linear search fallback).** Because a class can implement arbitrarily many unrelated interfaces, there's no single shared slot layout the way there is for a linear `extends` chain — so calling a method through an interface reference uses `invokeinterface`, historically resolved via a per-class **itable** (interface method table) or, in older/simpler JVM implementations, a linear scan of the class's interface method map. Modern HotSpot builds and caches itables per class specifically to avoid the slower linear search, and the JIT aggressively inlines and de-virtualizes these calls once it has observed the call site is monomorphic (sees only one concrete receiver type) — the same inline-caching idea used for ordinary virtual calls (see the Prototypes topic's JS equivalent — the underlying "monomorphic/polymorphic/megamorphic" inline cache classification is a shared JIT technique across V8 and HotSpot, not JavaScript-specific).

**`instanceof` and casting are runtime checks against the class metadata, not the vtable.** `(Derived) obj` compiles to a `checkcast` bytecode instruction that walks the object's actual class hierarchy metadata (not the vtable) to verify the cast is legal, throwing `ClassCastException` if not — this is a genuinely separate mechanism from method dispatch, even though both ultimately consult the object header's class pointer.

## Common Pitfalls

1. **Calling an overridable method from a constructor** — the superclass constructor runs before subclass field initializers, so an overridden method invoked mid-construction can observe uninitialized subclass state (see the OOP Fundamentals topic's "Under the Hood" for exactly why: `invokespecial` for the constructor happens first, but the vtable slot for the overridden method already points at the subclass's version).
2. **Overriding `equals()` without `hashCode()` (or vice versa)** — violates the contract that equal objects must have equal hash codes, silently breaking `HashMap`/`HashSet` lookups (see the Collections Framework topic) even though nothing throws an exception.
3. **Assuming fields are polymorphic like methods** — `base.label` in section 4 resolves by declared type, not runtime type; this trips up anyone coming from a language where all member access is virtual.
4. **Accidentally overloading instead of overriding** — a subtle signature mismatch (wrong parameter type, missing/extra parameter) creates a brand-new overload rather than an override, and without `@Override` the compiler won't warn you; the superclass version silently keeps running for callers using the superclass type.
5. **Widening a checked exception in an override** — a subclass override may only throw the same, narrower, or no checked exceptions than the method it overrides — never a broader or unrelated checked exception — because callers coded against the superclass type never expect it.

## Quick Reference

```java
class Dog extends Animal {                 // single inheritance only
    Dog(String name) { super(name); }      // super(...) must be first statement
    @Override String speak() { ... }        // @Override catches signature mismatches
}

interface Movable {                          // multiple interfaces allowed
    void move(int dx, int dy);
    default String info() { return "..."; } // Java 8+ default method
}

abstract class Shape {                       // cannot instantiate directly
    abstract double area();                  // subclass MUST implement
}

Base b = new Derived();
b.overriddenMethod();  // Derived's version  — methods: runtime type wins
b.field;                 // Base's version     — fields: declared type wins

// Object contract: override equals + hashCode together, always
```
