Java polymorphism and method overriding at runtime
runtime polymorphism, dynamic dispatch, upcasting, downcasting, instanceof check, abstract classes, abstract methods
Polymorphism
Polymorphism lets you write code against a supertype and have the correct subtype method execute at runtime. This decouples callers from specific implementations and makes code extensible without modification.
Runtime Dispatch
Animal a1 = new Dog("Rex", "Lab"); // upcasting
Animal a2 = new Cat("Luna");
System.out.println(a1.speak()); // Rex barks! — Dog's version
System.out.println(a2.speak()); // Luna meows! — Cat's version
The variable type (Animal) is the compile-time type. The object type (Dog, Cat) is the runtime type. The JVM always dispatches to the runtime type's method when an override exists.
Abstract Classes
public abstract class Shape {
public abstract double area(); // no body — subclasses must implement
public void describe() {
System.out.println("Area: " + area());
}
}
public class Circle extends Shape {
private double radius;
public Circle(double r) { this.radius = r; }
@Override
public double area() {
return Math.PI * radius * radius;
}
}
Shape s = new Circle(5);
s.describe(); // Area: 78.53...
instanceof checks before downcasting:
if (a1 instanceof Dog d) { // pattern matching (Java 16+)
System.out.println(d.getBreed());
}
An abstract class cannot be instantiated directly. It may contain both abstract methods (no body) and concrete methods (with body). Use it when subclasses share meaningful behavior but differ in at least one operation.
