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 Subsystem 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:
Subsystem s1 = new Subsystem("Generic");
Subsystem s2 = new Intake("Front Intake"); // legal — an Intake IS-A Subsystem
Subsystem s3 = new Climber("Left Climber"); // legal — a Climber IS-A Subsystem
The reverse doesn't work — a subclass-typed variable cannot hold a plain superclass object, since not every Subsystem is specifically an Intake:
Intake i = new Subsystem("Generic"); // ERROR — a Subsystem isn't necessarily an Intake
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 a whole robot's subsystems from one place possible:
public void stopAll(Subsystem[] subsystems)
{
for (Subsystem s : subsystems)
{
s.stop(); // works for an Intake, a Climber, a Shooter — anything extending Subsystem
}
}
Subsystem[] robotSubsystems = { new Intake("Front"), new Climber("Left"), new Shooter("Main") };
stopAll(robotSubsystems);
The same holds for collections — an ArrayList<Subsystem> happily holds Intake, Climber, and Shooter objects side by side:
ArrayList<Subsystem> allSubsystems = new ArrayList<Subsystem>();
allSubsystems.add(new Intake("Front"));
allSubsystems.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 Subsystem-typed variable holding an Intake object still calls Intake's own overridden methods, if it has any.
Common Pitfalls
- Trying to assign a superclass object to a subclass-typed variable.
Intake i = new Subsystem(...);is a compile error — not everySubsystemis anIntake. This only ever works the other direction (superclass variable, subclass object). - Thinking a
Subsystem[]array can only hold plainSubsystemobjects. It can hold any mix ofSubsystemand 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
Subsystem, calling a method on it runs the object's real class's version — not necessarilySubsystem's own.
Key Takeaways
- Several subclasses inheriting from one common superclass form an inheritance hierarchy, with
Objectat 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 subsystem 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)