dev only

Inheritance, Superclass, Subclass

What Inheritance Does

Inheritance lets one class inherit fields and methods from another. The class being inherited from is the superclass (or parent class); the class doing the inheriting is the subclass (or child class). Every FRC robot's subsystems share real structure — a name for logging, a stop() method, a periodic() method WPILib calls every loop — which makes them a natural fit for a shared superclass:

public abstract class Subsystem
{
    private String name;

    public Subsystem(String name) { this.name = name; }
    public String getName() { return name; }
    public void log(String msg) { System.out.println("[" + name + "] " + msg); }
}

public class Intake extends Subsystem
{
    // inherits getName() and log() for free
}

extends is the keyword that sets up inheritance. A Java class can only extends one superclass — unlike a person with two biological parents, there's no multiple inheritance of this kind in Java. Omitting extends entirely doesn't mean "no parent" — it means the class implicitly inherits from Java's built-in Object class (Lesson 17.4).

The is-a Relationship

Inheritance should only model a genuine is-a relationship: an Intake is a Subsystem, a Climber is a Subsystem. The test to apply: could you substitute the subclass anywhere the superclass is expected, and have it still make sense? A Vision processor being asked to stop() and get log()ed makes sense as a Subsystem — but a Robot class itself, or a Controller wrapping a joystick, isn't a kind of Subsystem, even if it happens to interact with one.

is-a vs. has-a

The has-a relationship (also called association) is different: it's when one class simply holds a reference to another, without being a specialized kind of it. A Robot has a Drivetrain, an Intake, and a Shooter — it isn't a subclass of any of them:

public class Robot
{
    private Drivetrain drivetrain;  // has-a: Robot holds a Drivetrain, isn't one
    private Intake intake;          // has-a
}

Compare that to Intake extends Subsystem — that's is-a: an Intake really is a specialized kind of Subsystem, not just something that happens to reference one.

Why Bother

Two forces motivate reaching for a superclass:

  • Generalization — several classes already share data/behavior, so pull the shared parts up into one common parent. Intake, Shooter, and Climber all need a name and a log() method — that's exactly what Subsystem is for.
  • Specialization — a class wants most of a parent's behavior, but needs to add something of its own or do one thing differently. Intake inherits log() unchanged, but still needs its own stop() that's specific to its own motor.

Common Pitfalls

  • Using inheritance purely to reuse code, without a real is-a relationship. If the substitution test fails — the subclass wouldn't actually make sense wherever the superclass is expected — model it as has-a (a field) instead of extends.
  • Forgetting a class always has exactly one superclass. Omitting extends doesn't mean "no parent" — it means the implicit parent is Object (Lesson 17.4).
  • Assuming a class can extend more than one class. class Intake extends Subsystem, Loggable doesn't compile — Java allows only one extends, though a class can implement multiple interfaces.

Key Takeaways

  • extends declares inheritance: the subclass gains the superclass's fields and methods.
  • A class can only extends one superclass; omitting extends implicitly means extending Object.
  • Use inheritance only for a genuine is-a relationship — verify with the substitution test (does the subclass make sense wherever the superclass is expected?).
  • has-a (association: one class simply holding a reference to another) is the right model when is-a doesn't genuinely apply.

Derived from csawesome-2026: unit-5-inheritance-optional/5.01-inheritance-superclass-subclass.md (CSA 5.1) Deck context: mechacoder-test/src/lessons/java-2.js, slide 4 ("Inheritance & Abstractions")