Java · Object-Oriented Java

Polymorphism

Polymorphism lets one piece of code work with many types, each behaving in its own way.

Beginner 5 min Lesson 14 of 31Examples target Java 21 LTS (they also run on Java 25).
Before you start:Inheritance
0/31 in Java
On this page · 5 min · Beginner

In simple words#

Pressing “Pay” works for UPI, card or wallet — each pays differently, but the checkout screen doesn’t care which one it has.

Dynamic dispatch
The real object’s method runs at runtime.
Upcasting
Storing a child in a parent-type variable.
instanceof pattern
if (p instanceof Upi u) { … } checks and casts.

Learning objectives#

  • Use parent-type references
  • Explain dynamic dispatch
  • Distinguish overloading and overriding
  • Use instanceof pattern matching

Explanation#

A variable of a parent type (or interface) can hold any child object: Payment p = new UpiPayment().

Calling p.pay() runs the child’s overridden method — decided at runtime.

Overloading is decided at compile time by parameter types; overriding at runtime by the object type.

instanceof with a pattern variable (Java 16+) checks the type and casts in one step.

Code example: One checkout, many payment types#

JavaOne checkout, many payment types Illustrative
import java.util.List;


abstract class Payment {
    abstract String pay(double amount);
}
class UpiPayment extends Payment {
    String pay(double amount) { return "Paid ₹" + amount + " via UPI"; }
}
class CardPayment extends Payment {
    String pay(double amount) { return "Charged ₹" + (amount + amount * 0.02) + " to card (2% fee)"; }
}


public class Checkout {
    public static void main(String[] args) {
        List<Payment> payments = List.of(new UpiPayment(), new CardPayment());
        for (Payment p : payments) {
            System.out.println(p.pay(1000));       // each object decides
            if (p instanceof CardPayment card) {
                System.out.println("  → card receipt for " + card.getClass().getSimpleName());
            }
        }
    }
}
Expected output
Paid ₹1000.0 via UPI
Charged ₹1020.0 to card (2% fee)
  → card receipt for CardPayment

This example is illustrative. Copy or download it and run it in your own environment; the expected output is shown above.

Step-by-step explanation#

  1. The list holds Payment references.
  2. p.pay() calls the right subclass method at runtime.
  3. Adding WalletPayment needs no change to Checkout.
  4. instanceof with a pattern variable casts safely.

Real-world use case#

Notification services send Email, SMS and WhatsApp messages through one Notifier interface.

Common mistakes#

Long if/else chains on type

Move behaviour into the classes and let polymorphism choose.

Confusing overloading with overriding

Overloading = same name, different params; overriding = child replaces parent method.

Best practices#

  • Program to the parent type or interface
  • Let objects decide their behaviour
  • Use instanceof patterns sparingly
  • Add new types without changing callers

Remember this#

Parent reference, child behaviour.

Override = runtime; overload = compile time.

New types plug in without changing callers.

Practice exercise#

Your task: Add a WalletPayment that returns "Paid from wallet".

Show solution
Java Illustrative
class WalletPayment extends Payment {
    String pay(double amount) { return "Paid ₹" + amount + " from wallet"; }
}

Mini quiz#

Polymorphism quizMultiple choice Question 1 of 1

When is an overridden method chosen?

Score so far: 0/0

Want more? Practise all Java MCQs · Java interview questions

My notes#

Saved in this browser.

Progress is saved in this browser. Sign in to sync.