Method Overloading in Java with Examples

In Java, it is possible to define two or more methods within the same class that share the same name, as long as their parameter declarations are different. When this is the case, the methods are said to be overloaded, and the process is referred to as method overloading. The compiler will resolve the call to a correct method depending on the actual number and/or types of the passed parameters.
The main advantage of method overloading increases the readability of the program.
Method overloading is one of the ways that Java supports polymorphism. If you have never used a language that allows the overloading of methods, then the concept may seem strange at first. But as you will see, method overloading is one of Java’s most exciting and useful features.
When an overloaded method is invoked, Java uses the type and/or a number of arguments as its guide to determine which version of the overloaded method to actually call. Thus, overloaded methods must differ in the type and/or a number of their parameters.
You cannot overload methods with the methods differing in return types alone.
You cannot overload methods with the methods differing in exception specifications alone.

Method Overloading Example

Here is a simple example that illustrates method overloading:
package com.javaguides.corejava.basics.polymorphism;

public class MethodOverloading {
    public static void main(String[] args) {
        OverloadDemo ob = new OverloadDemo();
        double result; // call all versions of test()
        ob.test();
        ob.test(10);
        ob.test(10, 20);
        result = ob.test(123.25);
        System.out.println("Result of ob.test(123.25): " + result);
    }
}

// Demonstrate method overloading.
class OverloadDemo {
    void test() {
        System.out.println("No parameters");
    }

    // Overload test for one integer parameter.
    void test(int a) {
        System.out.println("a: " + a);
    }

    // Overload test for two integer parameters.
    void test(int a, int b) {
        System.out.println("a and b: " + a + " " + b);
    }

    // Overload test for a double parameter
    double test(double a) {
        System.out.println("double a: " + a);
        return a * a;
    }
}
Output:
No parameters
a: 10
a and b: 10 20
double a: 123.25
Result of ob.test(123.25): 15190.5625
As you can see, test( ) is overloaded four times. The first version takes no parameters, the second takes one integer parameter, the third takes two integer parameters, and the fourth takes one double parameter. The fact that the fourth version of test( ) also returns a value is of no consequence relative to overloading since return types do not play a role in overload resolution.

Three ways to overload a method

In order to overload a method, the argument lists of the methods must differ in either of these:
  1. Number of parameters.
  2. Data type of parameters.
  3. Sequence of Data type of parameters

1. Different Number of parameters

In this example, we will overload 3 version of average() methods with a different number of parameters.
package com.javaguides.corejava.basics.polymorphism;

public class MethodOverloading {
    public static void main(String[] args) {
        ChangeNoOfArg changeNoOfArg = new ChangeNoOfArg();
        int avg = changeNoOfArg.avarage(10, 20);
        System.out.println("averageof 10 and 20 :: " + avg);
        avg = changeNoOfArg.average(10, 20, 30);
        System.out.println("averageof 10, 20 and 30 :: " + avg);
        avg = changeNoOfArg.average(10, 20, 30, 40);
        System.out.println("averageof 10, 20, 30 and 40 :: " + avg);
    }
}

class ChangeNoOfArg {
    public int average(int a, int b, int c) {
        return (a + b + c) / 3;
    }

    public int average(int a, int b) {
        return (a + b) / 2;
    }

    public int average(int a, int b, int c, int d) {
        return (a + b + c + d) / 4;
    }
}
Output:
averageof 10 and 20 :: 15
averageof 10, 20 and 30 :: 20
averageof 10, 20, 30 and 40 :: 25
Note that the first average(int a, int b, int c) method has three parameters, second average(int a, int b) method has 2 parameters and third average(int a, int b, int c, int d) has 4 parameters.
average(int a, int b, int c)
average(int a, int b)
average(int a, int b, int c, int d)

2 Difference in a data type of parameters

This example demonstrates that a number of parameters are same but having a difference in the data type of parameters.
package com.javaguides.corejava.basics.polymorphism;

public class MethodOverloading {
    public static void main(String[] args) {
        ChangeDataTypeOfArg changeDataTypeOfArg = new ChangeDataTypeOfArg();
        int avg = changeDataTypeOfArg.average(10, 20, 30);
        System.out.println("Avarage of 10, 20 and 30 :: " + avg);
        avg = changeDataTypeOfArg.average(10, 20, 30);
        System.out.println("Avarage of 10, 20 and 30 :: " + avg);
        avg = changeDataTypeOfArg.average(10, 20, 30);
        System.out.println("Avarage of 10, 20 and 30 :: " + avg);
    }
}

class ChangeDataTypeOfArg {
    public double average(double a, double b, double c) {
        return (a + b + c) / 3;
    }

    public int average(int a, int b, int c) {
        return (a + b + c) / 3;
    }

    public long average(long a, long b, long c) {
        return (a + b + c) / 3;
    }
}
Output:
Avarage of 10, 20 and 30 :: 20
Avarage of 10, 20 and 30 :: 20
Avarage of 10, 20 and 30 :: 20

3. A sequence of a data type

This example demonstrates that the number of parameters is the same but a sequence of data type is different.
package com.javaguides.corejava.basics.polymorphism;

public class MethodOverloading {
    public static void main(String[] args) {
        ChangeArgSeq changeArgSeq = new ChangeArgSeq();
        double avg = changeArgSeq.average(10, 20.0, 30.0);
        System.out.println("Avarage of 10, 20 and 30 :: " + avg);
        avg = changeArgSeq.average(10.0, 20, 30.0);
        System.out.println("Avarage of 10, 20 and 30 :: " + avg);
        avg = changeArgSeq.average(10.0, 20.0, 30);
        System.out.println("Avarage of 10, 20 and 30 :: " + avg);
    }
}

class ChangeArgSeq {
    public double average(int a, double b, double c) {
        return (a + b + c) / 3;
    }

    public double average(double a, int b, double c) {
        return (a + b + c) / 3;
    }

    public double average(double a, double b, long c) {
        return (a + b + c) / 3;
    }
}
Output:
Avarage of 10, 20 and 30 :: 20.0
Avarage of 10, 20 and 30 :: 20.0
Avarage of 10, 20 and 30 :: 20.0

Overload resolution

When you define overloaded methods, how does the compiler know which method to call? Can you guess the output of the code?
package com.javaguides.corejava.basics.polymorphism;

public class MethodOverloading {
    public static void main(String[] args) {
        byte b = 9;
        aMethod(b); // first call
        aMethod(9); // second call
        Integer i = 9;
        aMethod(i); // third call
        aMethod("9"); // fourth call
    }

    public static void aMethod(int val) {
        System.out.println("int");
    }

    public static void aMethod(short val) {
        System.out.println("short");
    }

    public static void aMethod(Object val) {
        System.out.println("object");
    }

    public static void aMethod(String val) {
        System.out.println("String");
    }
}
Output:
short
int
object
String
Here is how the compiler resolved these calls:
  • In the first method call, the statement is aMethod(b) where the variable b is of type byte. There is no aMethod definition that takes byte as an argument. The closest type (in size) is a short type and not int, so the compiler resolves the call aMethod(b) to aMethod(short val) definition.
  • In the second method call, the statement is aMethod(9). The constant value 9 is of type int. The closest match is aMethod(int), so the compiler resolves the call aMethod(9) to aMethod(int val) definition.
  • The third method call is aMethod(i), where the variable i is of type Integer. There is no aMethod definition that takes Integer as an argument. The closest match is aMethod(Object val), so it is called. Why not aMethod(int val)? For finding the closest match, the compiler allows implicit upcasts, not downcasts, so aMethod(int val) is not considered.
  • The last method call is aMethod("9"). The argument is a String type. Since there is an exact match, aMethod(String val) is called.
This process of the compiler trying to resolve the method call from given overloaded method definitions is called overload resolution. For resolving a method call, it first looks for the exact match—the method definition with an exactly the same number of parameters and types of parameters. If it can’t find an exact match, it looks for the closest match by using upcasts.

Method Overloading and Type Promotion

One type is promoted to another implicitly if no matching datatype is found. Let's understand the concept by the figure given below:
As displayed in the above diagram, the sequence of each type promotion:
byte → short → int → long
short → int → long
int → long → float → double
float → double
long → float → double

Example of Method Overloading with type promotion

package com.javaguides.corejava.basics.polymorphism;

public class MethodOverloading {
    void sum(int a, long b) {
        System.out.println(a + b);
    }

    void sum(int a, int b, int c) {
        System.out.println(a + b + c);
    }

    public static void main(String args[]) {
        MethodOverloading obj = new MethodOverloading();
        obj.sum(20, 20); // now second int literal will be promoted to long
        obj.sum(20, 20, 20);
    }
}
Output:
40
60
If the compiler can’t find any match, then you’ll get a compiler error:
package com.javaguides.corejava.basics.polymorphism;

public class MethodOverloading {
    public static void main(String[] args) {
        aMethod(9);
    }

    public static void aMethod(byte val) {
        System.out.println("byte");
    }

    public static void aMethod(short val) {
        System.out.println("short");
    }
}
Compiler Error:
The method aMethod(byte) in the type MethodOverloading is not applicable for the arguments (int)
The type of constant 9 is int, so there is no matching definition for aMethod for the call aMethod(9). As you saw earlier with respect to the overload resolution, the compiler can do upcasts (e.g., byte to int) for the closest match, but it does not consider downcasts (e.g., int to byte or int to short, as in this case). Hence, the compiler does not find any matches and throws you an error.
What if the compiler finds two matches? It will also become an error:
package com.javaguides.corejava.basics.polymorphism;

public class MethodOverloading {
    public static void main(String[] args) {
        aMethod(9, 10);

    }

    public static void aMethod(long val1, int val2) {
        System.out.println("long, int");
    }

    public static void aMethod(int val1, long val2) {
        System.out.println("int, long");
    }
}
Compiler Error:

Why did this call become an “ambiguous” call? The constants 9 and 10 are ints. There are two aMethod definitions: one is aMethod(long, int) and another is aMethod(int, long). So there is no exact match for the call aMethod(int, int). An integer can be implicitly upcasted to both long as well as Integer. Which one will the compiler choose? Since there are two matches, the compiler complains with an error that the call is ambiguous.

Summary

  • Method Overloading is a feature that allows a class to have more than one method having the same name if their argument lists are different.
  • In order to overload a method, the argument lists of the methods must differ in either of these: Number of parameters, Data type of parameters and Sequence of Data type of parameters
  • Overload resolution takes place entirely at compile time.
  • You cannot overload methods with the methods differing in return types alone.
  • You cannot overload methods with the methods differing in exception specifications alone.
  • For overload resolution to succeed, you need to define methods such that the compiler finds one exact match. If the compiler finds no matches for your call or if the matching is ambiguous, the overload resolution fails and the compiler issues an error.

Comments