One Name, Several Versions
On the previous page you saw how a method's parameters define what it accepts. Method overloading takes that further: you can give several methods the same name as long as their parameter lists differ. The compiler treats them as distinct methods and picks the right one based on the arguments you pass.
This is why System.out.println happily prints an int, a String, a boolean, or a double - there isn't one println, there are many overloads sharing the name. You write the call you mean and the compiler matches it to the version that fits.
Both methods are named square, but one takes an int and the other a double. The literal 5 is an int, so the first overload runs; 2.5 is a double, so the second runs.
What Counts as a Different Overload
Overloads must differ in their parameter list - that means at least one of:
- a different number of parameters,
- different parameter types, or
- a different order of types.
Each call has a parameter list that matches exactly one of the three join methods, so there is no confusion.
The Return Type Does Not Count
A common beginner trap: trying to overload on return type alone. The return type is not part of the signature the compiler uses, so this fails to compile:
// Does NOT compile - same name, same parameters, only the return type differs
static int value() { return 1; }
static double value() { return 1.0; } // error: value() is already defined
The compiler can't tell these apart, because at a call site like value() nothing in the arguments hints at which one you want. You may give overloads different return types, but only when their parameter lists already differ.
How Java Picks an Overload
When more than one overload could accept your arguments, Java chooses the most specific one and prefers an exact type match over a widening conversion. Watch what happens with an int argument:
show(7) matches int exactly even though long and double could also hold a 7 after widening. Only if the exact overload were removed would the compiler widen int to long, then to double. This resolution is decided entirely at compile time, based on the declared types of your arguments.
Watch Out for Ambiguous Calls
If no single overload is clearly the best match, the compiler refuses to guess and reports an error. This happens most often with null, which fits any reference type:
static void handle(String s) { }
static void handle(StringBuilder b) { }
handle(null); // error: reference to handle is ambiguous
Both overloads accept null, and neither is more specific, so the call won't compile. Fix it by making the type explicit with a cast - handle((String) null) - or by redesigning so the overloads don't collide. The same care applies when mixing autoboxing and widening; keep overload sets simple enough that every call has one obvious winner.
Overloading Constructors
Overloading isn't limited to ordinary methods - constructors use it constantly to offer several ways to build an object. A no-argument constructor can hand off to a fuller one with this(...):
The two constructors share the name Point but differ in parameter count, exactly like overloaded methods. Delegating with this(...) keeps the initialization logic in one place.
Overloading vs Overriding
These two sound alike but are unrelated:
- Overloading - same name, different parameter lists, in the same class. The compiler picks the version at compile time. It's about offering variants of an operation.
- Overriding - a subclass redefines an inherited method with the same name and the same parameters. Java picks the version at runtime based on the object's real type. It's about replacing behavior (you'll meet it under inheritance and polymorphism).
If the parameter lists are identical, you're overriding (or causing a duplicate-method error in the same class); if they differ, you're overloading.
Next: Varargs
Overloading lets you write join(a, b) and join(a, b, c) as separate methods - but what if you want to accept any number of arguments without declaring an overload for each count? Java's varargs syntax lets a single method take a variable-length argument list, and that's the next page.
Frequently Asked Questions
What is method overloading in Java?
Method overloading means defining several methods with the same name in the same class, each with a different parameter list (different number of parameters, different types, or a different order of types). The compiler decides which version to call by matching the arguments you pass against each overload's parameters. It is a compile-time decision, not a runtime one.
Can two methods differ only by return type in Java?
No. The return type is not part of a method's signature for overloading, so int total() and double total() in the same class is a compile error. Overloads must differ in their parameter list - the number, types, or order of parameters. The return type can differ, but only in addition to a parameter difference, not on its own.
What is the difference between overloading and overriding in Java?
Overloading is multiple methods with the same name but different parameters in the same class, resolved by the compiler at compile time. Overriding is a subclass redefining an inherited method with the same name and same parameters, resolved at runtime based on the object's actual type. Overloading is about offering variants; overriding is about replacing behavior.