Polymorphism is one of those words that sounds intimidating but is actually a simple idea. It comes from Greek โ "poly" meaning many and "morph" meaning form. So polymorphism means many forms.
In Java, polymorphism means the same method name can behave differently depending on the object calling it. There are two ways this happens: method overriding and method overloading.
Method Overriding (Runtime Polymorphism)
You already saw this with inheritance. A subclass provides its own version of a method that the parent already defined. Java decides which version to run at runtime.
class Animal {
void sound() {
System.out.println("Some sound");
}
}
class Dog extends Animal {
void sound() {
System.out.println("Bark");
}
}
class Cat extends Animal {
void sound() {
System.out.println("Meow");
}
}
public class Main {
public static void main(String[] args) {
Animal a1 = new Dog();
Animal a2 = new Cat();
a1.sound();
a2.sound();
}
}
Look closely โ both variables are declared as Animal, but the actual
objects are Dog and Cat. Java looks at the real object type
at runtime and calls the right sound() method. That is dynamic binding.
Polymorphism in Action
Here is where it gets powerful. You can write one method that works with any subclass
of Animal.
class Animal {
void sound() {
System.out.println("Some sound");
}
}
class Dog extends Animal {
void sound() {
System.out.println("Bark");
}
}
public class Main {
public static void makeItSound(Animal a) {
a.sound();
}
public static void main(String[] args) {
makeItSound(new Dog());
makeItSound(new Animal());
}
}
The makeItSound() method does not care what kind of Animal
you pass. It just calls sound() and trusts Java to figure out the right
version. That is polymorphism doing the heavy lifting.
Method Overloading (Compile-Time Polymorphism)
Overloading is when you have multiple methods with the same name but different parameters in the same class. Java picks the right one based on what you pass.
class Calculator {
int add(int a, int b) {
return a + b;
}
int add(int a, int b, int c) {
return a + b + c;
}
double add(double a, double b) {
return a + b;
}
}
public class Main {
public static void main(String[] args) {
Calculator calc = new Calculator();
System.out.println(calc.add(2, 3));
System.out.println(calc.add(2, 3, 4));
System.out.println(calc.add(2.5, 3.2));
}
}
Three methods, all named add. Java knows which one to call by looking
at the number and types of arguments. Overloading happens at compile time โ that is
why it is called compile-time polymorphism.