Inheritance Hierarchies

Multiple Subclasses, One Superclass

An inheritance hierarchy forms when several subclasses inherit (directly, or through another subclass) from a common superclass. Intake, Shooter, and Climber all extending RobotPart (each with a constructor that passes its name to super(...), like Intake's) is a small hierarchy; Object sits at the very top of every hierarchy in Java, since every class ultimately inherits from it (Lesson 17.4).

A Superclass Reference Can Hold Any Subclass Object

A variable typed as the superclass can refer to an object of that class or any of its subclasses:

RobotPart p1 = new RobotPart("Generic");
RobotPart p2 = new Intake("Front Intake");   // legal — an Intake IS-A RobotPart
RobotPart p3 = new Climber("Left Climber");  // legal — a Climber IS-A RobotPart

The reverse doesn't work — a subclass-typed variable cannot hold a plain superclass object, since not every RobotPart is specifically an Intake:

// ERROR — a RobotPart isn't necessarily an Intake
Intake i = new RobotPart("Generic");

Why This Matters: One Parameter Type, Every Subclass

A method, array, or collection typed against the superclass automatically accepts every subclass too — this is what makes managing all of a robot's parts from one place possible:

public void stopAll(RobotPart[] parts)
{
    for (RobotPart p : parts)
    {
        // works for an Intake, a Climber, a Shooter — anything extending RobotPart
        p.stop();
    }
}

RobotPart[] parts = { new Intake("Front"), new Climber("Left"), new Shooter("Main") };
stopAll(parts);

The same holds for collections — an ArrayList<RobotPart> happily holds Intake, Climber, and Shooter objects side by side:

ArrayList<RobotPart> allParts = new ArrayList<RobotPart>();
allParts.add(new Intake("Front"));
allParts.add(new Climber("Left"));

Which Method Actually Runs?

When a method typed against the superclass is called on an object that's actually a subclass instance, Java runs that object's actual version of the method — decided by its real runtime type, not the variable's declared type. This is the foundation of polymorphism, covered in full in Lesson 18.3 — for now, the key idea is just that a RobotPart-typed variable holding an Intake object still calls Intake's own overridden methods, if it has any (overriding, Lesson 18.1).

Common Pitfalls

  • Trying to assign a superclass object to a subclass-typed variable. Intake i = new RobotPart(...); is a compile error — not every RobotPart is an Intake. This only ever works the other direction (superclass variable, subclass object).
  • Thinking a RobotPart[] array can only hold plain RobotPart objects. It can hold any mix of RobotPart and its subclasses — that flexibility is the entire point of typing the array against the superclass.
  • Forgetting which method version actually runs. Even though a variable is declared RobotPart, calling a method on it runs the object's real class's version — not necessarily RobotPart's own.

Key Takeaways

  • Several subclasses inheriting from one common superclass form an inheritance hierarchy, with Object at the top of every hierarchy in Java.
  • A superclass-typed variable, array, or collection can hold objects of that class or any of its subclasses — never the reverse.
  • This lets one method signature, one array type, or one collection type work seamlessly across an entire family of related robot-part classes.
  • Which method actually executes depends on the object's real runtime type, not the variable's declared type — the basis of polymorphism (Lesson 18.3).

Derived from csawesome-2026: unit-5-inheritance-optional/5.05-inheritance-hierarchies.md (CSA 5.5)