Polymorphism
Overloading: same method name, different parameters — like add(int,int) and add(double,double). Decided at compile-time.
Overriding: a child class redefines a parent's method in its own way — like Dog defining its own sound(). Decided at run-time.
class Animal { void sound() { System.out.println("..."); } }
class Cat extends Animal { void sound() { System.out.println("Meow"); } }- One name, many forms
- Overloading = same class, different parameters
- Overriding = child redefines parent's method
Overloading happens when there are multiple methods with the same name, but different parameters (number, type, or order). The compiler decides which method to call at compile-time itself, by looking at the arguments' types — which is why it's called "compile-time" (or "static") polymorphism.
Return type alone can't be the basis for overloading — two methods differing only by return type are considered "the same" (a compile error).
void print(int x) { System.out.println("int: " + x); }
void print(String x) { System.out.println("String: " + x); }
void print(int x, int y) { System.out.println("two ints"); }Overriding happens between a parent and child — the child gives its own version of the parent's method (with the same signature). Which version runs is decided at *runtime*, based on the actual object's type (not the reference type) — which is why it's called "runtime" (or "dynamic") polymorphism.
The most powerful example: a Parent-type reference can point to a Child-type object (Animal a = new Dog();). When you call a method, the JVM looks at the *actual object* (Dog, not the reference type Animal), and runs its overridden version.
This is exactly what enables polymorphic code — handling every Animal type in a single loop, whether it's a Dog, a Cat, or any future subclass of Animal — without ever changing the loop's code.
Animal a = new Dog(); // parent reference, child object
a.makeSound(); // Dog ka version chalega, Animal ka nahi!
for (Animal animal : zooList) { // List<Dog>, List<Cat> — sab Animal type
animal.makeSound(); // har ek ka apna sahi version chalega
}Polymorphism lets you write generic code that will keep working with new types in the future, without changing existing code — this is called the "Open/Closed Principle" (open for extension, closed for modification).
Like keeping Circle, Square, Triangle all in a List<Shape> and calling area() on each — from a single loop; adding a new shape (Pentagon) later won't require changing the loop at all, just build a Pentagon class that extends Shape.