Overloading vs. Overriding in a Shape Hierarchy
A student defines:
class Shape {
public double area() { return 0; }
public String describe() { return "shape"; }
}
class Circle extends Shape {
private double r;
public Circle(double r) { this.r = r; }
public double area() { return Math.PI * r * r; }
public String describe() { return "circle"; }
public String describe(String prefix) { return prefix + "circle"; }
}
Then:
Shape s = new Circle(2.0);
System.out.println(s.describe());
System.out.println(s.area());
prints circle and 12.56.... A teammate adds public String describe(String prefix) to Shape and claims it changes which method s.describe("big ") calls. The student is also confused why s.describe("big ") does not compile even though s refers to a Circle.
1. Explain why `s.describe()` prints `circle` but `s.describe("big ")` does not compile, and distinguish overloading from overriding here.
Read the worked answer
The static type of s is Shape. Method resolution for a call compiles against the static type.
s.describe()-Shapedeclares a no-argdescribe().Circleoverrides it, so at runtime dynamic dispatch callsCircle.describe(), printingcircle.s.describe("big ")-Shapehas no one-argdescribe(String). That method exists only onCircle, so the compiler rejects the call. Casting toCirclewould fix it:((Circle) s).describe("big ").
Circle.describe(String) is an overload of describe(), not an override - different parameter list. Overloading is resolved at compile time by static type; overriding is resolved at runtime by dynamic type. The two mechanisms are independent, which is why the no-arg call dispatches dynamically but the one-arg call fails to compile.
2. The teammate adds `public String describe(String prefix)` to `Shape` returning `prefix + "shape"`. Predict what `s.describe("big ")` prints with `s` still declared as `Shape` referencing a `Circle`, and justify.
Read the worked answer
Shape now declares a one-arg describe(String), so s.describe("big ") compiles. Circle declares a method with the same signature describe(String), so it overrides Shape's version. Dynamic dispatch therefore calls Circle.describe(String), printing big circle.
If Circle had not declared its own describe(String), the call would print big shape - the inherited Shape version. The judgment point: adding a method to the superclass can silently change which method a call resolves to, and can turn what was an overload into an override. That is a behavioral change the teammate should not make casually, because existing call sites through Shape references now route differently.