Polymorphism in Java: A Comprehensive Guide with Practical Examples
What is Polymorphism in Java?
Polymorphism is a core concept in Java’s Object‑Oriented Programming (OOP). It arises when classes are linked by inheritance, allowing a single interface to represent different underlying forms. The result is that a method call can invoke different implementations depending on the actual object type at runtime.
Think of a smartphone that can communicate by voice call, text, image, or email. The goal—communication—is the same, but each mode behaves differently. That’s polymorphism in everyday terms.
What You’ll Learn
- Definition of Java polymorphism
- Practical OOP examples
- Method overriding
- Overloading vs. overriding
- Dynamic (run‑time) polymorphism
- Static vs. dynamic polymorphism
- The
superkeyword
Java Polymorphism in OOPs: An Example
Consider a base class Account that offers deposit() and withdraw(). Two subclasses, SavingsAccount and CheckingAccount, inherit these methods unchanged because the operations are identical.

Adapting to Changing Requirements
When a new feature—such as an overdraft facility—is required, a PrivilegedAccount subclass can override withdraw() to provide the new logic without touching existing subclasses. This demonstrates the maintainability advantage of polymorphism.

Method Overriding in Java
Overriding occurs when a subclass supplies its own implementation of a method already defined in its superclass. The method signature (name, parameters, return type) must match exactly.
Key Rules
- The overridden method may have broader visibility (e.g.,
protectedtopublic) but never narrower. - Return types must be the same or covariant.
Example:
class Doctor {
public void treatPatient() {
// common treatment logic
}
}
class Surgeon extends Doctor {
@Override
public void treatPatient() {
// specialized surgical treatment
}
}
public class Run {
public static void main(String[] args) {
Doctor doctor = new Doctor();
doctor.treatPatient(); // executes Doctor.treatPatient()
Surgeon surgeon = new Surgeon();
surgeon.treatPatient(); // executes Surgeon.treatPatient()
}
}
Overloading vs. Overriding
| Method Overloading | Method Overriding |
|---|---|
| Same class, same name, different parameter list. | Superclass method redefined in subclass with identical signature. |
Example:void sum(int a, int b); |
Example:class X { int sum() { ... } }
class Y extends X { @Override int sum() { ... } } |
Dynamic Polymorphism (Run‑Time)
When a superclass reference points to a subclass object, the JVM resolves the method call at runtime. This is true polymorphism in action.
Doctor doc = new Surgeon(); doc.treatPatient(); // Executes Surgeon.treatPatient()
The actual method invoked depends on the object's runtime type, not the reference type.
Static vs. Dynamic Polymorphism
Static polymorphism (overloading) is resolved at compile time, while dynamic polymorphism (overriding) is resolved at runtime.
| Static Polymorphism | Dynamic Polymorphism |
|---|---|
| Method overloading; compile‑time binding. | Method overriding; runtime binding. |
Example:void sum(int a, int b); |
Example:Doctor d = new Surgeon(); |
Using the super Keyword
When a subclass needs to extend a superclass method, super calls the parent implementation before adding its own logic.
class Surgeon extends Doctor {
@Override
public void treatPatient() {
super.treatPatient(); // base logic
// surgeon‑specific logic
}
}
Similarly, super can access protected or public fields of the superclass.
Practical Example: Inheritance, Polymorphism, & Super
Copy the code below into your IDE and observe the output.
public class Test {
public static void main(String[] args) {
X x = new X();
Y y = new Y();
y.m2();
// Uncomment to see inheritance effects
// x.m1();
// y.m1();
// x = y; // parent reference to child object
// x.m1();
// y.a = 10; // error: a is private
}
}
class X {
private int a;
int b;
public void m1() {
System.out.println("This is method m1 of class X");
}
}
class Y extends X {
int c;
@Override
public void m1() {
System.out.println("This is method m1 of class Y");
}
public void m2() {
super.m1();
System.out.println("This is method m2 of class Y");
}
}
Key Takeaways
- Polymorphism allows objects to take multiple forms through inheritance.
- Method overriding changes behavior in subclasses while keeping the same signature.
- Dynamic polymorphism resolves method calls at runtime, enabling flexible code.
- Static polymorphism (overloading) is compile‑time, while dynamic polymorphism is run‑time.
- The
superkeyword lets subclasses invoke parent methods or access protected members.
Java
- Mastering Java Polymorphism: Concepts, Examples, and Best Practices
- Understanding C# Interfaces: Definition, Example, and Practical Use
- Mastering Abstraction in OOP: Java Abstract Classes & Methods Explained
- Encapsulation in Java: A Comprehensive Guide with Practical Example
- Understanding Java Classes and Objects: Clear Concepts, Practical Examples
- Understanding Java String.charAt(): Syntax, Return Type, Exceptions, and a Practical Example
- Mastering Java’s String.endsWith(): How to Check String Suffixes with Examples
- Java Inheritance Explained: Types, Syntax, and Practical Examples
- Java Abstraction: Mastering Abstract Classes, Methods, and Practical Examples
- Java Interfaces Explained: How to Define and Implement Them with Practical Examples