Method Overloading: Static Polymorphism in Java

Method overloading is a type of polymorphism in Java and other object-oriented programming languages that helps us to write cleaner and more maintainable code. Before understanding method overloading, let's understand the idea of methods in java.

Methods in Java

Methods are used to perform specific tasks or operations with an object. The main() method is the first method executed by the compiler when a Java program is run.

The signature of a method consists of the method name and the parameter list. For example, the method "addition" performs an addition operation and may have a signature like "int addition(int a, int b)".

Example of methods in Java

NOTE: The return type of the method is not considered in the signature of a method.

What is method overloading?

In Java, method overloading allows us to have multiple methods with the same name but with different argument lists. This is a static polymorphism (compile-time polymorphism) which helps us to perform a single task in different ways. This is also known as early binding.

By using method overloading, we can create multiple versions of a method with different implementations based on the arguments passed to it. So, this will help us to reuse the same method name for different purposes.

For example, consider the addition method again, but this time you are not sure whether you will have to add three integers or two integers. So we create two methods with the same name, but one with two integer parameters and the other with three integer parameters.

public class Calculator {
    // Method to add two integers
    public int addition(int a, int b) {
        return a + b;
    }
    
    // Method to add three integers
    public int addition(int a, int b, int c) {
        return a + b + c;
    }
}

When a method is called, the compiler checks the name and argument list of the method to determine which version of the method to call. If there are multiple methods with the same name but different argument lists, the compiler will choose the correct version of the method based on the arguments passed to it.

Calculator calc = new Calculator();
// calls the first version of the method
int sum1 = calc.addition(1, 2);  
// calls the second version of the method
int sum2 = calc.addition(1, 2, 3);

In the above example, if we call calc.addition(1, 2), the compiler will look for a method with the name "addition" that takes two integers as arguments. It will find the first version of the "addition" method and call it with the given arguments. Similarly, if we call calc.addition(1, 2, 3), the compiler will find the second version of the "addition" method and call it with the given arguments.

How to overload a method?

Each overloaded method must have a different argument list. This means that the number and/or types of arguments must be different between the overloaded methods. So there are three basic ways to create different argument lists.

Different number of arguments: One method takes more or fewer arguments than the other.

public class Calculator {
    // Method to add two integers
    public int addition(int a, int b) {
        return a + b;
    }
    
    // Method to add three integers
    public int addition(int a, int b, int c) {
        return a + b + c;
    }
}

Different types of arguments: One method takes different types of arguments than the other.

public class Calculator {
    // Method to add two integers
    public int addition(int a, int b) {
        return a + b;
    }
    
    // Method to add three integers
    public float addition(float a, float b, float c) {
        return a + b + c;
    }
}

Different order of arguments: One method takes arguments in a different order than the other.

public class Calculator {
    // Method to add two integers
    public float addition(int a, float b) {
        return a + b;
    }
    
    // Method to add three integers
    public float addition(float a, int b) {
        return a + b + c;
    }
}

Important points to consider when using overloaded methods in Java.

  • We can have multiple methods with the same name but different return types, as long as they take different arguments. But changing the return type alone is not sufficient to overload a method. The argument lists of the methods must also be different.
  • Overloaded methods can be present within the same class or in different classes within an inheritance hierarchy. In the latter case, the subclass can overload a method inherited from the superclass.
  • Static methods can be overloaded in the same way as non-static methods. However, if two methods only differ in being static or non-static and have the same signature, they are not considered overloaded methods.
  • Overloaded methods can have different access modifiers, such as public, private, or protected. However, the access modifier does not contribute to method overloading. Only the method name and parameter lists are considered.
  • Overloading constructors is a common use case of method overloading. It allows the creation of multiple constructors with different parameter lists to initialize objects in different ways.
  • Method overloading should be used carefully to avoid confusion. The idea is simple: We need to ensure that the overloaded methods have clear and distinct functionalities to prevent unintended behaviour.

Why method overloading?

  1. Method overloading eliminates the need to create separate methods with different names to perform similar operations. So it improves the code maintainability and code organization.
  2. By using intuitive method names, developers can easily identify the purpose of each overloaded method based on the parameters. So it makes the code more readable and understandable.
  3. Method overloading enables flexibility by selecting the appropriate method based on the data types or the number of arguments passed.

For example, in the code below, multiple methods with different names are used to perform various types of addition. This will make the code less readable. If we use the same name for all of the methods, then it will definitely improve the readability and make the code easier to understand.

int addTwo (int first , int second) {
    //Implementation code
}
int addThree (int first , int second , int third) {
    //Implementation code
}
String addStringNum (int first , String second) {
    //Implementation code
}

Type promotion and method overloading

Consider the following definition of work() method and call to work():

void work (long num) {
     System.out.println(num);
}
//...
//calling work() with an int value
int test = 0;
work (test);

This code can run without errors because the Java compiler automatically promotes the variable "test" to a higher data type. One can refer to this chart for type promotion in Java:

chart for type promotion in Java method overloading

Things get interesting when we consider type promotion in overloaded methods. Let’s see how? When a method is invoked, the Java compiler will first try to find an exact match based on the argument list. If it cannot find a match, it will attempt to promote the data type of the arguments to a higher type and check for a match again. This process will continue until a match is found or the promotion chain is completed.

If the promotion chain is completed without finding a match, the compiler will report a compile-time error. This is because the arguments cannot be promoted any further, and there is still no matching method available.

Example 1

public class TypePromo{

    public void method(long first) {
        System.out.println("Long "+ first);
    }
    
    public void method(float first) {
        System.out.println("Float "+ first);
    }
    
    
    public static void main(String args[]) {
        TypePromo obj = new TypePromo();
        obj.method(21);
    }
}
//int gets promoted to long

Output: Long 21

Example 2: Ambiguity error in method overloading

public class TypePromo {

    public void method(int first, double second) {
        System.out.println(first + second);
    }
    
    public void method(double first, int second) {
        System.out.println(first + second);
    }
    
    
    public static void main(String args[]) {
        TypePromo obj = new TypePromo();
        obj.method(14 , 14);
    }
}

This code results in a compilation error: "The method(int, double) is ambiguous for the type TypePromo".This is because both types of method() are applicable after type promotion which arises an ambiguity of which method to invoke. This is the ambiguity error.

Conclusion

In this blog, you learned about method overloading in Java, including:

  1. How does method overloading work?
  2. Types of method overloading
  3. Benefits of method overloading
  4. Different ways to implement method overloading, along with examples.
  5. How type promotion affects method overloading?

Thanks to Ankit Nishad for his contribution in creating the first version of this content. If you have any queries or feedback, please write us at contact@enjoyalgorithms.com. Enjoy learning, enjoy OOPS!

More from EnjoyAlgorithms

Self-paced Courses and Blogs