What is the difference between method overloading and method overriding in Java, and when does each one happen?
Overloading is compile time polymorphism; overriding is run time polymorphism. In overloading, several methods share a name in the same class but take different parameter lists, and the compiler picks one based on the static types of the arguments at the call site. Nothing about it depends on the object involved. In overriding, a subclass declares a method with the same signature as one in its superclass, and the JVM picks the implementation based on the actual type of the object at run time.
That difference explains why the two look so similar in code but behave differently. In the example below, the same call site resolves the overload at compile time from the argument types, while the overridden method is chosen at run time from the object's real class even though the variable is declared as the base type.
public class Main {
public static void main(String[] args) {
Printer printer = new LaserPrinter();
// Overloading: resolved by the compiler from the argument types.
System.out.println(printer.print("hello"));
System.out.println(printer.print(7));
// Overriding: resolved at run time from the object's real type.
System.out.println(printer.describe());
}
}
class Printer {
String print(String text) { return "overload(String): " + text; }
String print(int number) { return "overload(int): " + number; }
String describe() { return "base describe"; }
}
class LaserPrinter extends Printer {
@Override
String describe() { return "overridden describe"; }
}Overriding has strict rules that make it safe: the name and parameter list must match exactly, the return type must be identical or covariant, the access modifier cannot be tightened, checked exceptions cannot be broadened, and the method must not be final or private, and the class must not be final. The @Override annotation is not required, but putting it on every overriding method turns those rules into compile-time checks instead of silent conventions, which is why it is close to mandatory in modern code.