Skip to main content

Java OOP

Polymorphism

Complete lesson for Polymorphism using LEARNCODEGURU’s 6-level learning model — from basics to advanced practice, with Java OOP and Collections where relevant.

L1

Basics — Polymorphism

Section: Java OOP. Compile-time overloading vs runtime overriding: the heart of Java OOP interviews.

One name, many forms

  • **Compile-time (static) polymorphism:** overloading — the compiler picks the method from the *argument types* and *reference type*.
  • **Runtime (dynamic) polymorphism:** overriding — the JVM picks the method from the *actual object* (virtual dispatch).
  • Upcast: Animal a = new Dog(); The compile-time type is Animal; the runtime type is Dog.
class Payment {
    void pay(int amount) {
        System.out.println("pay " + amount);
    }
}

class Upi extends Payment {
    @Override
    void pay(int amount) {
        System.out.println("UPI " + amount);
    }
}

public class PolyDemo {
    public static void main(String[] args) {
        Payment p = new Upi();
        p.pay(99); // UPI 99 — runtime type wins
    }
}

Overload vs override

OverloadOverride
BindingCompile timeRuntime
SignatureName same, params differName + params same (erasure)
ReturnCan differ (not only that)Same or covariant
Static / private / finalCan overloadCannot override these
AccessIndependentCannot be more restrictive
ExceptionsIndependentCannot add new checked exceptions

@Override and covariant returns

  • @Override is optional but should be mandatory in your style. It catches equals(Payment) when you meant equals(Object).
  • A subclass may return a more specific type (Animal copy() → Dog copy()).
L2

Advanced — Polymorphism

What is not polymorphic

  • Fields are not overridden — they are hidden. super.x vs subclass x depends on the *reference* type.
  • Static methods are hidden, not overridden. Parent ref = new Child(); ref.staticM(); calls Parent.staticM.
  • private methods are not visible to subclasses, so they are not overridden; a subclass method with the same name is unrelated.
  • Downcast ((Dog) a) fails with ClassCastException if the runtime type is wrong. Prefer instanceof (pattern matching on Java 16+).
L3

Tricky Interview Points

Q1) What is polymorphism in Java?

Answer The ability to treat objects through a common type. Overloading is compile-time; overriding is runtime dispatch on the actual class.

Q2) Why does Payment p = new Upi(); p.pay() call Upi?

Answer pay is an instance method. The JVM looks up the method in the runtime class (Upi), not the reference type (Payment).

Q3) Can you override a static method?

Answer No. You hide it. Which method runs depends on the compile-time type.

Q4) Rules for a valid override?

Answer Same name and parameters, covariant return allowed, same or weaker access restriction, no new checked exceptions, not static/final/private.

Q5) What is covariant return type?

Answer The override may return a subtype of the original return type.

Q6) Is operator overloading polymorphism in Java?

Answer Java does not allow user-defined operator overloading. + for String is built in.

L4

Simple Programs

Array of superclass references

abstract class Notify {
    abstract void send(String msg);
}

class Email extends Notify {
    @Override
    void send(String msg) {
        System.out.println("email: " + msg);
    }
}

class Sms extends Notify {
    @Override
    void send(String msg) {
        System.out.println("sms: " + msg);
    }
}

public class NotifyAll {
    public static void main(String[] args) {
        Notify[] channels = {new Email(), new Sms()};
        for (Notify n : channels) {
            n.send("OTP 4412");
        }
    }
}
L5

Problem Solving Tricks

  • Always @Override. It is the cheapest interview-quality habit.
  • Program to the superclass/interface, construct the concrete class.
  • Do not override equals without hashCode.
  • If you need the subclass extra methods, you probably should not have upcast — or those methods belong on the parent/interface.
L6

Practice Programs List

  1. Create Instrument with play() and two subclasses; store them in an Instrument[].
  2. Overload play(int times) in one subclass and show that an Instrument reference cannot see the overload.
  3. Hide a static method and print which version runs from parent vs child references.
  4. Hide a field int x and print parentRef.x vs ((Child) parentRef).x.
  5. Write equals/hashCode for a Money class and put it in a HashSet.