Java Programs›OOP›Interfaces & Polymorphism

Interfaces & Polymorphism in Java

intermediate·  OOP  ·  Interfaces

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

Java
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

Area: 28.27 Area: 20.00

Core Logic

Two unrelated classes implement the same interface here, and calling the same method through it produces different behavior depending on the object.

How It Works
  1. 1interface Shape declares an area() method with no implementation.
  2. 2Circle and Rectangle each implements Shape and supply their own formula for area().
  3. 3Both objects are stored in a single Shape[] array, even though they're different concrete classes.
  4. 4The loop calls s.area() on each element — the same method call, resolved to a different implementation depending on the object's actual class.
The same 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

interfaceimplementspolymorphism

Approach 2: Java 8

Java
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

Area: 28.27 Area: 20.00

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.

How It Works
  1. 1default String describe() is added directly to the Shape interface, with a real method body instead of just a signature.
  2. 2Inside describe(), calling area() resolves polymorphically to whichever class the interface reference actually points to, the same as any other interface method call.
  3. 3Neither Circle nor Rectangle needs to implement describe() — they inherit it automatically just by implementing Shape.
  4. 4The loop calls s.describe() instead of formatting the output itself, moving that formatting logic into the interface.
Calling 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

default methodinterfacepolymorphism

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.

Learn the Concept

Related Programs