dev only

Overriding Methods

What Overriding Is

A subclass inherits all its superclass's public methods unchanged — but it can also override one, replacing the inherited version with its own. Overriding requires matching the superclass method's exact signature: same name, same parameter list, and the same (or a subtype of the) return type.

public abstract class Subsystem
{
    public void stop() { System.out.println("Stopping subsystem"); }
}

public class Intake extends Subsystem
{
    @Override
    public void stop()
    {
        motor.set(0); // Intake's own, specific version replaces Subsystem's
    }
}

@Override is optional but always worth writing — it tells the compiler "I intend to override an inherited method here," and the compiler then checks the signature truly matches. Without it, a typo in the method name (stopp() instead of stop()) would silently create a brand-new, unrelated method instead of overriding anything — with @Override, that same typo becomes a compile error instead of a bug that only shows up at runtime.

Overriding vs. Overloading

These sound similar but are entirely different things. Overriding means the exact same signature, in a subclass, replacing the superclass's version. Overloading means the same method name, in the same class, with a different parameter list:

public class Subsystem
{
    public void log(String message) { System.out.println(message); }
    public void log(String message, int code) { System.out.println(message + " [" + code + "]"); } // overload — different parameters
}

Two methods can never differ only in return type — that alone doesn't count as a valid overload, and doesn't count as an override either (a mismatched return type on an otherwise-identical signature is just a compile error).

Inherited Getters and Setters Still Apply

A subclass gets its superclass's public getters and setters automatically, and — since the superclass's fields are private — those accessor methods remain the only way to reach them, even from the subclass itself:

public class Subsystem
{
    private String name;
    public String getName() { return name; }
    public void setName(String name) { this.name = name; }
}

public class Intake extends Subsystem
{
    public void rename(String newName)
    {
        setName(newName); // must go through the inherited setter — direct access to `name` isn't legal here
    }
}

Common Pitfalls

  • Mismatching the signature and expecting an override anyway. Changing the parameter list (even by adding one parameter) makes it an overload, not an override — the original method is still inherited unchanged, sitting alongside the new one.
  • Forgetting @Override. Skipping it doesn't break anything when the signature is right, but it removes the compiler's safety net against typos — always include it when overriding.
  • Trying to differ only by return type. public int stop() next to a superclass's public void stop() doesn't compile — that's neither a valid override nor a valid overload.

Key Takeaways

  • Overriding replaces an inherited method with a new version in the subclass, using the exact same signature (name, parameters, return type).
  • @Override isn't required, but should always be used — it turns a signature typo into a compile error instead of a silent, unrelated new method.
  • Overloading is different: same name, same class, different parameter list — not to be confused with overriding.
  • Two methods can never differ only in return type.
  • Inherited getters/setters remain the only way to reach a superclass's private fields, even from within the subclass.

Derived from csawesome-2026: unit-5-inheritance-optional/5.03-overriding-methods.md (CSA 5.3) Deck context: mechacoder-test/src/lessons/java-2.js, slide 5 ("Polymorphism: Many Forms")