Method Overloading in Java

Naveen AnamaneniUpdated · 6 min read

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

Billing.java▶ Try it
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));
    }
}
Output
250.0
1000.0
900.0

How it works

  1. Three methods share the name total. Their parameter lists differ in number: one, two and three parameters.
  2. For each call, the compiler matches the arguments to a version: total(250.0, 4) fits only the two-parameter one.
  3. The choice is fixed at compile time and stored in the .class file.

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

ChangeValid 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 differNo
Only static or access modifiers differNo

Changing only the return type is a compile error, because a call like sum(2, 3) couldn't tell the two apart:

Compiler output
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 error

How 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:

Widening beats boxing; boxing beats varargs
Pick.java▶ Try it
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);
    }
}
Output
f(long)
g(String)
g(Object)

How it works

  1. f(5) passes an int. No f(int) exists, so phase 1 tries widening: int to long works, and the compiler stops there. Boxing to Integer (phase 2) and varargs (phase 3) are never tried.
  2. g(null): null fits both Object and String. The compiler picks the most specific one, String, because every String is an Object but not the reverse.
  3. g(o) passes a variable declared as Object. The compiler only knows the declared type, so it picks g(Object), even though the object is a String at runtime.

Ambiguous Calls

If two overloads are equally specific, the call doesn't compile:

Amb.java
public class Amb {
    static void g(String s) {}
    static void g(StringBuilder s) {}
    public static void main(String[] a) { g(null); }
}
Compiler output
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 error

Neither 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

  1. Easy: Overload max for two ints, three ints and two doubles, and call each.
  2. Harder: Predict, then check: with show(int), show(long) and show(double), what do show('A'), show(5L) and show(5.0f) print?

Quick check: Method overloading

4 questions
1Which pair is a valid overload?
2With f(long) and f(Integer), what does f(5) call?
3Object o = "Navika"; g(o); with g(Object) and g(String) calls:
4When is overloading resolved?

Key Takeaways

Was this tutorial helpful?

Lesson 122 of 482