What is overloading

Overloading means creating with the same name but different arguments.
Arguments may differ in number or types.
Either methods or constructors can be overloaded in java.

What is method overloading
Method overloading means creating different methods with the same name but with different number or type of arguments.
Return type of overloaded methods may be same or different, doesn’t matter.
Only thing that makes methods overloaded is their argument list.

Thus, following points should be remembered for overloaded methods.

  • Overloaded methods MUST have different number or type of arguments.
  • Overloaded methods CAN have different access modifiers. That is, it is legal for one method to be private while other method to be protected.
  • Overloaded methods CAN throw different exceptions.
  • Overloaded methods CAN have different return types.
    Two overloaded methods can return a String and an Integer.

Benefits of method overloading
Overloaded methods are suitable in below scenarios

  • When creating an application, method names should be meaningful and indicate the purpose of the method.
    Often, more than a single method perform the same function and thus should have the same name. Method overloading makes it possible.
  • Further, for large methods, it often makes sense to break them into more than one where second method is provided required arguments making it private since it is required for internal use only.
    Both the methods perform the same function, it is sensible to give same name to both of them.

Method overloading example
Below program demonstrates method overloading where 4 methods are created with same name but with different number or type of arguments.

public class OverloadDemo {

   // 2 argument method
   public void printDetails(String name, int rollNo) {
      System.out.println("Name: " + name + ", Roll No.: " + rollNo);
   }

   // single int argument method
   public void printDetails(int rollNo) {
      System.out.println("Roll No.: " + rollNo);
   }

   // single String argument method
   public void printDetails(String name) {
      System.out.println("Name: " + name);
   }

   // 3 argument method
   public void printDetails(String name, int rollNo, String class) {
      System.out.println("Name: " + name + ", Class: " + class +
             ", Roll No.: " + rollNo);
   }

   public static void main(String[] args) {
      OverloadDemo obj = new OverloadDemo();
      // call one argument string method
      obj.printDetails("John");
      // call one argument int method
      obj.printDetails(56);
      // call 3 argument method
      obj.printDetails("John", 56, "10th");
      // call 2 argument method
      obj.printDetails("John", 56);
   }
} 

Above program produces the following output

Name: John
Roll No.: 56
Name: John, Class: 10th, Roll No.: 56
Name: John, Roll No.: 56

Method overloading and Widening
Suppose there are two overloaded methods, one accepting an int and other a long and you call this method with 5 as argument.
Which method should be invoked?

When there are two overloaded methods, one accepting a smaller data type and other accepting a bigger one, then first the exact matching method will be found and called.

If the exact match could not be found, then the method accepting next higher data type is invoked.
Example,

public class OverloadDemo {
   public void wideningOverload(int a) {
 	System.out.println("int");
   }
	
   public void wideningOverload(long a) {
	System.out.println("long");
   }
   
   public void wideningOverload(double a) {
	System.out.println("double");
   }
   
   public static void main(String[] args) {
	new OverloadDemo().wideningOverload(10);
   }
}

Above program contains three overloaded methods each accepting an int, long and double respectively.
This method is called passing it 10 as argument and it prints int.
This is because 10 is an integer and first method is an exact match.
If the first method is removed, then it will print long, since out of long and double, long is the closest match.

Below table briefly explains the widening flow that is applicable.

Argument Type while calling Argument match Explanation
byte short, int, long, float, double If a method with byte argument is not found, then the method with argument as given in the previous column will be matched in the same order.
short int, long, float, double If a method with short argument is not found, then the method with argument as given in the previous column will be matched in the same order.
int long, float, double If a method with int argument is not found, then the method with argument as given in the previous column will be matched in the same order.
long float, double If a method with long argument is not found, then the method with argument as given in the previous column will be matched in the same order.
float double If a method with float argument is not found, then the method accepting a double argument is matched.
double No matching data types If a method with double argument is not found, then a compiler error will be raised when trying to call the method.
char int, long, float, double If a method with char argument is not found, then the method with argument as given in the previous column will be matched in the same order.

Widening also applies to objects.
That is, if there is a method accepting a super class as argument, then it can be called passing it an object of its sub-type as argument.
Example,

public class OverloadDemo {
   // method accepting a super class
   public void wideningOverload(Animal a) {
 	System.out.println("Animal");
   }
	
   public static void main(String[] args) {
        // create object of child class
        Dog dog = new Dog();
	new OverloadDemo().wideningOverload(dog); // allowed
   }
}

where Dog is the child class of Animal.

Method Overloading and Boxing
Suppose there are two overloaded methods, one accepting a primitive type and other its wrapper class.

Example, an int and java.lang.Integer and you call this method with 10 as argument. Which method should be invoked?
Answer is again exact match.

In this case, since method accepting int argument exactly matches, it will be called.
Now, suppose there are again two methods, one accepting long and another a java.lang.Integer.
In this case, method with long argument will be called.

This is because when there are options of widening and Boxing, then widening will be preferred.
Thus, in this case 10 can be widened to a long, hence method with long argument is executed.
Ambiguous method error in overloading
As mentioned above, which overloaded methods to invoke is decided on the basis of values provided while invoking the method.

There are times when the compiler is unable to determine which method to invoke after looking at the value supplied probably because the values match with arguments of more than one methods.
In such cases, it raises an ambiguous method error.
Typical scenario is

public class OverloadDemo {
 
   public void printNumber(Double number) {
	System.out.println("Double");
   }
 
   public void printNumber(Integer number) {
      System.out.println("Integer");
   }
 
   public static void main(String[] args) {
	new OverloadDemo().printNumber(null);
   }
}

Above class contains two overloaded methods: one accepts a java.lang.Integer and another accepts a java.lang.Double as argument.
While invoking this method with null value, the compiler cannot determine which method to call since both methods can be called with this and it raises an error

OverloadDemo.java:13: error: reference to printNumber is ambiguous
new OverloadDemo().printNumber(null);
^
both method printNumber(Double) in OverloadDemo and method printNumber(Integer) in OverloadDemo match
1 error

In order to resolve the above error, we need to tell the type of value we are supplying while calling an overloaded method.
Thus, instead of passing null directly, if we assign it some type, then compiler will be able to identify which method to invoke.
Consider modified code below.

public class OverloadDemo {
 
   public void printNumber(Double number) {
 	System.out.println("Double");
   }
 
   public void printNumber(Integer number) {
      System.out.println("Integer");
   }
 
   public static void main(String[] args) {
       // create a variable of type Double
       // and initialize it to null  
       Double number = null;
       // supply it as method argument
       new OverloadDemo().printNumber(number); // prints Double
   }
}

Now the compiler knows that it needs to call the method which accepts a java.lang.Double argument and the error goes away.
Can we overload main method
The answer is yes.
Main method can also be overloaded.
You can create multiple methods with name main accepting different argument types or numbers or both in a class.
Thus, below program is perfectly legal.

public class OverloadDemo {
	
   public void main(long a) {
	System.out.println("long");
   }
   
   public void main(double a) {
	System.out.println("double");
   }
   
   public static void main(String[] args) {
	new OverloadDemo().main(10);
   }
}

But remember, when the program is executed, JVM will always look for a main method which is public, static, void and which accepts a java.lang.String array.
Can we overload static methods
Yes.
static methods can also be overloaded just like instance methods. Same rules and invoking logic applies to them also.
But you can not create a static and a non-static method with the same name and same number and type of arguments in a class.
Thus, below code will be a compiler error.

public class OverloadDemo {
   public static void wideningOverload(int a) {
 	System.out.println("int");
   }
	
   public void wideningOverload(int a) {
	System.out.println("long");
   }
}

Constructor overloading in java
Just as we can overload methods in a class, constructors can also be overloaded.
This makes sense since constructors are also methods with name same as the class name.
Example,

public class OverloadDemo {
  // default constructor
  public OverloadDemo () {
      System.out.println("No-arg constructor");     
  }
   
  // constructor with int argument
  public OverloadDemo (int a) {
      System.out.println("int argument constructor");
  }
	
  // constructor with double argument
  public OverloadDemo (double a) {
      System.out.println("long argument constructor");
  }   
  
  public static void main(String[] args) {
      // create objects 
      new OverloadDemo();
      new OverloadDemo(10);
      new OverloadDemo(20.5);
  }
}

Above code calls constructors as per the arguments supplied while creating objects and produces the below output.

No-arg constructor
int argument constructor
long argument constructor

Operator overloading in java
Java does not support operator overloading as allowed in other languages such as C++.

Do share this post if it helped you out in understanding the concept of overloading in java.

Leave a Reply