Difference Between Method Overloading and Method Overriding in Java
Method overloading and method overriding both let one method name have several implementations, but they work in completely different ways:
- Overloading: same name, different parameter lists, usually in the same class. The compiler picks the method from the argument types (compile-time polymorphism).
- Overriding: same name and same parameters, in a subclass. The JVM picks the method from the actual object at run time (runtime polymorphism).
1. Comparison Table
| Aspect | Overloading | Overriding |
|---|---|---|
| Definition | Same name, different parameters | Subclass redefines an inherited method with the same signature |
| Where | Same class (or added in a subclass) | Superclass/interface and subclass |
| Parameters | Must differ (number, type or order) | Must be identical |
| Return type | Can be anything | Same, or a subtype (covariant) |
| Access modifier | Can be anything | Same or wider |
| Checked exceptions | Can be anything | Same, narrower or none |
| Resolved | At compile time (static binding) | At run time (dynamic binding) |
| Based on | Declared types of arguments | Actual class of the object |
| Polymorphism type | Compile-time | Runtime |
| Inheritance needed | No | Yes |
static methods | Can be overloaded | Cannot be overridden (only hidden) |
private / final methods | Can be overloaded | Cannot be overridden |
| Annotation | None | @Override recommended |
| Purpose | Convenience: one name for related operations | Specialisation: subclass-specific behaviour |
2. Both in One Example
public class OverloadVsOverride {
static class Printer {
// OVERLOADING: same name, different parameters, same class
void print(String text) { System.out.println("Printer text: " + text); }
void print(String text, int n) { for (int i = 0; i < n; i++) print(text); }
// To be OVERRIDDEN by the subclass
String header() { return "Plain"; }
void printHeader() { System.out.println("Header: " + header()); }
}
static class ColorPrinter extends Printer {
// OVERRIDING: same signature, subclass, decided at run time
@Override String header() { return "Color"; }
// OVERLOADING across inheritance: a new parameter list
void print(String text, String color) { System.out.println("Printer " + color + ": " + text); }
}
public static void main(String[] args) {
Printer p = new ColorPrinter(); // reference type Printer, object type ColorPrinter
p.print("Hello"); // overload chosen by compiler
p.print("Hi", 2); // another overload
p.printHeader(); // override chosen at run time -> Color
// p.print("x", "red"); // compile error: Printer has no print(String, String)
((ColorPrinter) p).print("Hello", "red");
}
}
Printer text: Hello Printer text: Hi Printer text: Hi Header: Color Printer red: Hello
print(String)andprint(String, int)are overloads: the compiler chooses between them.header()is overridden: even thoughpis declared asPrinter, theColorPrinterversion runs.print(String, String)in the subclass is an overload added through inheritance. It is not visible through aPrinterreference.
3. Compile-Time vs Run-Time Choice
The clearest way to see the difference is to combine both in one call. The overload is picked by the declared type of the argument; the override is picked by the actual object:
public class BindingTimeDemo {
static class Animal { String speak() { return "..."; } }
static class Dog extends Animal { @Override String speak() { return "Woof"; } }
// Overloads: chosen by the DECLARED type of the argument (compile time)
static String describe(Animal a) { return "describe(Animal) -> " + a.speak(); }
static String describe(Dog d) { return "describe(Dog) -> " + d.speak(); }
public static void main(String[] args) {
Animal a = new Dog(); // declared Animal, actually a Dog
Dog d = new Dog();
System.out.println(describe(a)); // overload by declared type: Animal; override by object: Woof
System.out.println(describe(d));
}
}
describe(Animal) -> Woof describe(Dog) -> Woof
For describe(a), the compiler only knows a is an Animal, so it selects describe(Animal). Inside, a.speak() is an overridden method, so the JVM runs Dog.speak().
4. When to Use Which
- Use overloading to offer convenient variants of the same operation:
log(String),log(String, Throwable); constructors with optional parameters. - Use overriding when a subclass must behave differently for an operation defined by the parent or interface:
toString(),area(),processPayment().
5. Common Mistakes
- Writing
equals(MyClass o)instead ofequals(Object o): that overloads instead of overriding.@Overridecatches it. - Expecting overloads to be chosen by runtime type; they are not.
- Trying to overload by return type only, which does not compile.
- Expecting static methods to behave polymorphically.
6. Summary
- Overloading: same name, different parameters; compile-time; no inheritance needed.
- Overriding: same signature in a subclass; run-time; requires inheritance.
- Overriding has strict rules for return types, access and exceptions; overloading has none beyond the parameter list.
- Static, private and final methods can be overloaded but not overridden.
Related Tutorials
Frequently Asked Questions (FAQ)
Q1. What is the main difference between overloading and overriding?
Overloading uses the same method name with different parameters and is resolved at compile time. Overriding redefines an inherited method with the same signature and is resolved at run time.
Q2. Which is compile-time and which is runtime polymorphism?
Overloading is compile-time polymorphism; overriding is runtime polymorphism.
Q3. Does overriding require inheritance?
Yes. A method can only be overridden by a subclass or an implementing class.
Q4. Does overloading require inheritance?
No. Overloads are usually declared in the same class, although a subclass can also add overloads.
Q5. Can return types differ in overloading?
Yes, if the parameter lists also differ. A return type difference alone is not enough.
Q6. Can return types differ in overriding?
Only covariantly: the overriding method may return a subtype of the original reference return type.
Q7. Can static methods be overloaded and overridden?
They can be overloaded but not overridden; a subclass static method with the same signature hides the parent's.
Q8. Can private methods be overloaded?
Yes, within the same class. They cannot be overridden, because they are not inherited.
Q9. Can final methods be overloaded?
Yes. final only prevents overriding.
Q10. Which is faster, overloading or overriding?
Overloaded calls are bound at compile time; overridden calls use dynamic dispatch. In practice the JIT optimises both, and the difference is negligible.
Q11. Can constructors be overloaded or overridden?
Constructors can be overloaded but never overridden, since they are not inherited.
Q12. Is @Override used for overloading?
No. Putting @Override on an overload causes a compile error, which is exactly how it catches accidental overloads.
Q13. Can the main method be overloaded or overridden?
It can be overloaded, but it cannot be overridden because it is static.
Q14. What is static binding vs dynamic binding?
Static binding links a call to a method at compile time (overloading, static, private, final). Dynamic binding links it at run time based on the object (overriding).
Q15. Can access modifiers differ in overloading?
Yes, freely. In overriding, access can only stay the same or become wider.
Q16. Can exceptions differ in overloading?
Yes, overloaded methods can declare any exceptions. Overriding methods cannot add new or broader checked exceptions.
Q17. Can a method be both overloaded and overridden?
Yes. A class can have several overloads of a name, and a subclass can override any of them individually.
Q18. Why does equals(MyClass) not override equals(Object)?
The parameter type differs, so it is an overload. Collections call equals(Object), which still uses the default identity comparison.
Q19. Is overloading decided by the runtime type of arguments?
No. The compiler uses the declared types of the argument expressions.
Q20. What are real-world examples of each?
Overloading: println(int), println(String), Math.max(int,int) and Math.max(double,double). Overriding: toString(), equals(), and run() in a Thread subclass.