Interfaces & Polymorphism in Java
Problem
An interface defines a contract of methods that any implementing class must provide, each in its own way.
Create a Shape interface implemented by both a Circle and a Rectangle class.
Java Program
interface Shape {
double area(); // no implementation — each class must supply its own
}
class Circle implements Shape {
double radius;
Circle(double radius) { this.radius = radius; }
public double area() { return Math.PI * radius * radius; }
}
class Rectangle implements Shape {
double w, h;
Rectangle(double w, double h) { this.w = w; this.h = h; }
public double area() { return w * h; }
}
public class ShapeDemo {
public static void main(String[] args) {
// Different concrete classes, stored through their shared interface type
Shape[] shapes = { new Circle(3), new Rectangle(4, 5) };
for (Shape s : shapes) {
// Same call, different implementation depending on the actual object
System.out.printf("Area: %.2f%n", s.area());
}
}
}Output
Core Logic
Two unrelated classes implement the same interface here, and calling the same method through it produces different behavior depending on the object.
- 1
interface Shapedeclares anarea()method with no implementation. - 2
CircleandRectangleeachimplements Shapeand supply their own formula forarea(). - 3Both objects are stored in a single
Shape[]array, even though they're different concrete classes. - 4The loop calls
s.area()on each element — the same method call, resolved to a different implementation depending on the object's actual class.
s.area() call prints 28.27 for the Circle and 20.00 for the Rectangle.Key Point: Programming against the Shape interface — instead of the concrete classes — is what lets new shapes be added later without touching this loop.
Key Concepts
Approach 2: Java 8
interface Shape {
double area(); // no implementation — each class must supply its own
// Default methods can have a real body, and every implementing class gets it for free
default String describe() {
return String.format("Area: %.2f", area());
}
}
class Circle implements Shape {
double radius;
Circle(double radius) { this.radius = radius; }
public double area() { return Math.PI * radius * radius; }
}
class Rectangle implements Shape {
double w, h;
Rectangle(double w, double h) { this.w = w; this.h = h; }
public double area() { return w * h; }
}
public class ShapeDemoDefaultMethod {
public static void main(String[] args) {
Shape[] shapes = { new Circle(3), new Rectangle(4, 5) };
for (Shape s : shapes) {
// describe() is inherited from the interface, not written in either class
System.out.println(s.describe());
}
}
}
Output
Core Logic
Java 8 let interfaces carry actual method bodies — a default method here can build on area() without either implementing class writing a line of extra code.
- 1
default String describe()is added directly to theShapeinterface, with a real method body instead of just a signature. - 2Inside
describe(), callingarea()resolves polymorphically to whichever class the interface reference actually points to, the same as any other interface method call. - 3Neither
CirclenorRectangleneeds to implementdescribe()— they inherit it automatically just by implementingShape. - 4The loop calls
s.describe()instead of formatting the output itself, moving that formatting logic into the interface.
s.describe() on the Circle internally calls its own area(), producing "Area: 28.27" — identical output to the manual printf call, just generated inside the interface.Key Point: Default methods let an interface evolve — like adding describe() here — without breaking every class that already implements it, which is exactly the problem they were introduced in Java 8 to solve.
Key Concepts
Interview Questions
How does an interface enable polymorphism?
A variable of the interface type can hold any implementing object, and calling a method runs that object's own version — so new implementations work without changing the calling code.
Is this resolved at compile time or run time?
At run time. The JVM looks at the actual object type when the method is called, which is called dynamic dispatch.