Problem Statement
Differentiate method overloading from method overriding and discuss their use-cases.
Explanation
Method overloading (compile-time polymorphism) and method overriding (runtime polymorphism) are often confused but serve different purposes. Overloading lets multiple methods in the same class share a name but differ in parameter lists—useful when you want to provide multiple ways to call a method (for example `print(int)` and `print(String)`). Overriding means a subclass provides its own version of a method defined in a superclass. Overriding is used when you want to alter or extend behavior in derived classes (for example `class Bird { fly() }` and `class Penguin extends Bird { fly() { throw new CannotFlyException(); } }`). Showing when and why to use each is key for interviews.