Polymorphism in Java
"For just as the body is one and has many members, and all the members of the body, though many, are one body, so it is with Christ." — 1 Corinthians 12:12
Why This Matters
A short chapter. The reason: you've already learned the ideas. Chapter 12 covered inheritance, virtual methods, polymorphic collections. The Java version is simpler than the C++ version — Java made better defaults.
What Java Does for You
| C++ | Java |
|---|---|
: public Vehicle | extends Vehicle |
Vehicle(w, m) in init list | super(w, m); |
virtual on base method | nothing — all methods virtual by default |
override on derived | @Override (annotation) |
virtual ~Class() | (no destructor needed) |
Vehicle* fleet[N] | Vehicle[] fleet or ArrayList<Vehicle> |
| slicing is a hazard | no slicing — refs only |
All Methods Virtual by Default
You don't write virtual in Java. Every non-static method dispatches dynamically.
The mechanism is the same as C++ — Java just turned it on universally. Cleaner default.
@Override — Cheap Insurance
public class Car extends Vehicle {
@Override
public void describe() { /* ... */ }
} @Override is technically optional. Always write it. If you
typo the method name, the compiler refuses to compile — saving you from the silent
"polymorphism doesn't work" bug.
No Slicing
In C++, void f(Vehicle v) slices off the derived parts when you pass a Car. In
Java, Vehicle is a reference type — passing it just passes the reference, so
the dynamic type is preserved. This whole class of bug goes away.
instanceof and Casting
for (Vehicle v : fleet) {
if (v instanceof Car c) {
System.out.println("car passengers: " + c.getPassengers());
}
}
Java 16+ has pattern-matching instanceof — checks the type and casts in one
step. Use sparingly. Heavy instanceof usually means a virtual method is
missing — refactor to add one.
Coach's Note — Java is, somewhat infamously, a language where inheritance gets overused. When we move through the standard library you'll see 4- and 5-level hierarchies that any modern engineer would refactor. Watch for it. Just because the language makes inheritance easy doesn't mean every problem wants it.
No Project This Week
Use the week to consolidate. Catch up on your Project 13 migration. Read Chapter 15's content (abstracts and interfaces) — both will be needed for the final.
Java Polymorphism — Quick Check
virtual keyword because all non-static methods are virtual by default. @Override is recommended (catches typos at compile time) but not strictly required. The dispatch happens regardless of whether you mark the override. public class Car extends Vehicle {
public void descrobe() { // ← typo, no @Override
// ...
}
} @Override, the compiler is happy to let you add a new method called descrobe. When you call vehicle.describe(), the base version runs — your "override" is never reached. Adding @Override would have caught the typo at compile time. Always write @Override. if (v instanceof Car) ... else if (v instanceof Truck) .... What does that usually indicate?instanceof chains are a smell: they're switch-on-type code that could be replaced by polymorphism. Add a virtual method on the base (e.g., describe() or getCapacity()) that each subclass overrides; replace the chain with one call. The compiler dispatches for you.