Skip to content
  • Polymorphism & Dynamic Dispatch · Java

Polymorphism & Dynamic Dispatch

LearnViaNotes @learnvianotes· 3 min read

One reference type, many behaviours: the JVM picks the overriding method of the actual object at runtime.

Runtime polymorphism

Java
import java.util.List;

public class Main {
    public static void main(String[] args) {
        List<Payment> payments = List.of(new Card(100), new Upi(250), new Cash(40));
        double total = 0;
        for (Payment p : payments) {             // one loop, three behaviours
            System.out.println(p.describe());
            total += p.fee();
        }
        System.out.println("total fees = " + total);
    }
}

abstract class Payment {
    protected final double amount;
    Payment(double amount) { this.amount = amount; }
    abstract double fee();
    String describe() { return getClass().getSimpleName() + " " + amount + " fee " + fee(); }
}

class Card extends Payment { Card(double a) { super(a); } double fee() { return amount * 0.02; } }
class Upi  extends Payment { Upi(double a)  { super(a); } double fee() { return 0; } }
class Cash extends Payment { Cash(double a) { super(a); } double fee() { return 1; } }
Output
Card 100.0 fee 2.0
Upi 250.0 fee 0.0
Cash 40.0 fee 1.0
total fees = 3.0

Static type vs runtime type

QuestionDecided byWhen
Which methods may I call?Reference (static) typeCompile time
Which overload is chosen?Static types of the argumentsCompile time
Which override runs?Runtime class of the objectRuntime (dynamic dispatch)
Which field is read?Reference type — fields are not polymorphicCompile time
Which static method runs?Reference typeCompile time

How dynamic dispatch works

  1. Compile

    javac checks the method exists on the static type and emits invokevirtual Shape.area() (or invokeinterface).

  2. Look up

    At runtime the JVM reads the object's actual class and finds area in its method table (vtable) — the most specific override.

  3. Optimise

    The JIT often inlines the call when only one implementation has been seen (monomorphic call site), so polymorphism is usually free.

Upcasting and downcasting

Java
public class Main {
    public static void main(String[] args) {
        Animal a = new Dog();              // upcast: implicit, always safe
        a.speak();
        // a.fetch();                      // error: Animal has no fetch()

        if (a instanceof Dog d) {          // pattern matching (Java 16+): test + cast
            d.fetch();
        }
        Dog d2 = (Dog) a;                  // explicit downcast: checked at runtime
        d2.fetch();

        Animal c = new Cat();
        try {
            Dog wrong = (Dog) c;           // compiles, fails at runtime
            wrong.fetch();
        } catch (ClassCastException e) {
            System.out.println("ClassCastException");
        }
    }
}

class Animal { void speak() { System.out.println("..."); } }
class Dog extends Animal {
    @Override void speak() { System.out.println("Woof"); }
    void fetch() { System.out.println("fetching"); }
}
class Cat extends Animal { @Override void speak() { System.out.println("Meow"); } }
Output
Woof
fetching
fetching
ClassCastException

Overloading is decided at compile time

Java
public class Main {
    static String greet(Object o) { return "object"; }
    static String greet(String s) { return "string"; }

    public static void main(String[] args) {
        Object o = "hello";            // runtime type String, static type Object
        System.out.println(greet(o));  // overload chosen from the STATIC type
        System.out.println(greet("hello"));
        System.out.println(o.toString().length());   // override chosen at runtime
    }
}
Output
object
string
5

What is dynamic method dispatch?

Are fields polymorphic?

Can you achieve polymorphism without inheritance?

Free for students and teachers

Write notes like this one

Cards for every idea, quizzes and flashcards, read aloud — on the web and your phone.

Something wrong with this note? Open it to report