Method Overloading in Java
A billing counter can total one item, several of the same item, or several items with a discount. It's the same job, "total", with different inputs. Method overloading lets you give all three methods the same name, as long as their parameter lists differ. The compiler reads each call and picks the matching version, which is why overloading is called compile-time polymorphism.
Same Name, Different Parameters
public class Billing {
static double total(double price) {
return price;
}
static double total(double price, int qty) {
return price * qty;
}
static double total(double price, int qty, double discountPercent) {
return price * qty * (100 - discountPercent) / 100;
}
public static void main(String[] args) {
System.out.println(total(250.0));
System.out.println(total(250.0, 4));
System.out.println(total(250.0, 4, 10));
}
}250.0
1000.0
900.0How it works
- Three methods share the name
total. Their parameter lists differ in number: one, two and three parameters. - For each call, the compiler matches the arguments to a version:
total(250.0, 4)fits only the two-parameter one. - The choice is fixed at compile time and stored in the
.classfile.
Try it yourself: add total(double price, int qty, String coupon) that takes Rs. 100 off when the coupon is "NAVIKA100".
What Counts as a Different Parameter List
| Change | Valid overload? |
|---|---|
Different number of parameters: area(double) and area(double, double) | Yes |
Different types: print(int) and print(String) | Yes |
Different order of types: pay(String, int) and pay(int, String) | Yes (but confusing) |
Only the return type differs: int sum(int, int) and long sum(int, int) | No |
| Only parameter names differ | No |
Only static or access modifiers differ | No |
Changing only the return type is a compile error, because a call like sum(2, 3) couldn't tell the two apart:
Ret.java:3: error: method sum(int,int) is already defined in class Ret
static long sum(int a, int b) { return a + b; }
^
1 errorHow the Compiler Chooses
When no overload matches the argument types exactly, the compiler tries conversions in a fixed order and stops at the first phase that finds a match:
public class Pick {
static void f(long x) { System.out.println("f(long)"); }
static void f(Integer x) { System.out.println("f(Integer)"); }
static void f(int... x) { System.out.println("f(int...)"); }
static void g(Object o) { System.out.println("g(Object)"); }
static void g(String s) { System.out.println("g(String)"); }
public static void main(String[] args) {
f(5);
g(null);
Object o = "Navika";
g(o);
}
}f(long)
g(String)
g(Object)How it works
f(5)passes anint. Nof(int)exists, so phase 1 tries widening:inttolongworks, and the compiler stops there. Boxing toInteger(phase 2) and varargs (phase 3) are never tried.g(null):nullfits bothObjectandString. The compiler picks the most specific one,String, because everyStringis anObjectbut not the reverse.g(o)passes a variable declared asObject. The compiler only knows the declared type, so it picksg(Object), even though the object is aStringat runtime.
Ambiguous Calls
If two overloads are equally specific, the call doesn't compile:
public class Amb {
static void g(String s) {}
static void g(StringBuilder s) {}
public static void main(String[] a) { g(null); }
}Amb.java:4: error: reference to g is ambiguous
public static void main(String[] a) { g(null); }
^
both method g(String) in Amb and method g(StringBuilder) in Amb match
1 errorNeither String nor StringBuilder is a subtype of the other, so neither is more specific. A cast fixes it: g((String) null).
In Practice
The JDK is full of overloads. System.out.println has ten of them (for int, long, double, char, String, Object and more), and Math.max has four. Overload when the methods do the same job on different inputs; if they do different jobs, give them different names.
Common Mistakes
Overloading on return type only. It's a compile error; change the parameters or the name.
Expecting the runtime type to choose the overload. g(o) with Object o = "Navika" calls g(Object).
Mixing boxing and varargs overloads. f(Integer) and f(int...) together make calls hard to predict; keep overload sets simple.
Interview Corner
What is method overloading, and can it be done by changing only the return type?
Overloading means defining several methods with the same name but different parameter lists (number, types or order of parameters) in the same class or inherited into it. The compiler picks the version from the argument types at compile time. Changing only the return type isn't allowed, because a call like sum(2, 3) couldn't tell the methods apart; the compiler reports that the method is already defined.
Which overload runs for
f(5) if there are f(long), f(Integer) and f(int...)?
f(long). The compiler first looks for a match using only exact types and widening, and int widens to long. Boxing is tried only if that phase fails, and varargs only after boxing fails.
Practice
- Easy: Overload
maxfor twoints, threeints and twodoubles, and call each. - Harder: Predict, then check: with
show(int),show(long)andshow(double), what doshow('A'),show(5L)andshow(5.0f)print?
Key Takeaways
Was this tutorial helpful?