Learning outcome: Distinguish method overloading from method overriding and apply the rules of each correctly.
Overloading gives several methods the same name with different parameter lists. Overriding lets a child class replace an inherited instance-method implementation.
Method Overloading
Methods are overloaded when they have the same name but different parameter lists in the same class or inheritance hierarchy.
In simple terms: Overloading is one word carrying several meanings, chosen by context — “book a table” and “read a book”. The compiler picks from the arguments supplied, before the program ever runs.
class Calculator {
static int add(int a, int b) {
return a + b;
}
static int add(int a, int b, int c) {
return a + b + c;
}
static double add(double a, double b) {
return a + b;
}
}
The compiler selects a method using the number, types, and order of arguments.
Valid Ways to Overload
| Change | Valid overload? | Example |
|---|---|---|
| Number of parameters | Yes | show(int) and show(int, int) |
| Parameter types | Yes | show(int) and show(String) |
| Parameter order | Yes, if the sequence of types differs | show(int, String) and show(String, int) |
| Return type only | No | int show() and double show() conflict |
| Parameter names only | No | Names are not part of a method signature |
Return type alone cannot resolve a call because a caller may ignore the returned value.
Type Promotion in Overloading
If no exact overload exists, Java may widen a compatible primitive argument.
In simple terms: With no exact match, Java widens rather than narrows: an int will happily be treated as a long, but never silently squeezed into a byte.
class PromotionDemo {
static void print(long value) {
System.out.println("long: " + value);
}
public static void main(String[] args) {
int number = 25;
print(number); // int widens to long
}
}
Avoid overload sets that make calls ambiguous. Clear APIs are more important than having many similar overloads.
Method Overriding
A child class overrides an inherited instance method by declaring a compatible method with the same signature.
In simple terms: Overriding is a child giving its own answer to a question the parent already answered. Which answer is used is decided while the program runs, from the actual object.
class Notification {
void send() {
System.out.println("Generic notification");
}
}
class EmailNotification extends Notification {
@Override
void send() {
System.out.println("Email sent");
}
}
Use @Override. It asks the compiler to confirm that a valid inherited method is being overridden.
Overriding Rules
| Rule | Meaning |
|---|---|
| Same method name and parameter list | The child method must match the inherited signature. |
| Compatible return type | It must be the same type, or a more specific reference type where covariance is allowed. |
| Access cannot be more restrictive | A public parent method cannot become protected or private. |
| Checked exceptions cannot be new or broader | The child may declare fewer checked exceptions or compatible subtypes, but not an unrelated or broader checked type; unchecked exceptions are not restricted by this rule. |
final methods cannot be overridden |
final fixes the inherited implementation. |
| Private methods are not overridden | They are not inherited as accessible methods. |
| Constructors are not overridden | Constructors belong to the class that declares them. |
Calling the Parent Implementation
Use super.methodName() when the child wants to extend, rather than completely replace, parent behaviour.
In simple terms: super.method() is adding to what the parent already does rather than replacing it — the parent’s work happens, then the child’s extra step.
class Report {
void print() {
System.out.println("Report header");
}
}
class SalesReport extends Report {
@Override
void print() {
super.print();
System.out.println("Sales data");
}
}
Static Methods and main
Static methods are associated with a class and are hidden, not overridden. Selection uses the reference type rather than the runtime object.
In simple terms: Static methods are hidden, not overridden. The reference type decides which one runs, so the polymorphism you would expect simply does not apply.
The main method can be overloaded, but on the JDK 17 course baseline the Java launcher starts the standard entry-point signature:
public static void main(String[] args)
The equivalent varargs spelling public static void main(String... args) is also valid because String... compiles as String[]. Other main overloads run only when called explicitly.
Overloading vs Overriding
| Feature | Overloading | Overriding |
|---|---|---|
| Purpose | Multiple ways to call related behaviour | Specialised child behaviour |
| Parameters | Must differ | Must match |
| Inheritance required | No | Yes |
| Binding | Compile time | Runtime for instance methods |
| Return type | May differ when parameters differ | Same or covariant |
| Static methods | Can be overloaded | Hidden, not overridden |
Common Mistakes
| Mistake | Correction |
|---|---|
| Changing only the return type | Change the parameter list instead. |
| Misspelling an overriding method | Add @Override so the compiler detects it. |
| Reducing visibility in a child method | Keep the same or broader access. |
| Expecting a static method to behave polymorphically | Static methods are hidden, not overridden; use instance methods for runtime dispatch. |
Practice
- Overload
area()for a square, rectangle, and circle. - Create an
Employeeparent whosecalculatePay()is overridden by two child classes. - Predict which overload runs when an
intis passed to methods acceptinglonganddouble. - Explain why
int convert(String)anddouble convert(String)cannot coexist.
Quick Check
1. Can two overloads differ only by return type?
No. Their parameter lists must differ.
2. Why should @Override be used?
It lets the compiler verify that the method correctly overrides an inherited method.
3. Are static methods overridden?
No. Static methods can be overloaded or hidden, but runtime overriding applies to instance methods.
Summary
Overloading is compile-time selection among methods with different parameter lists. Overriding supplies specialised child behaviour and enables runtime polymorphism. Correct signatures, access levels, return types, and exception rules keep both mechanisms predictable.