Thursday, December 4, 2014

Method Overloading

We want to start with our discussion on compile time polymorphism. To start with that, let's discuss a problem of printing the output on the console.

Now when we want to print something on console, we have to write a method something like the following,
/*
 * Copyright 2014-2016 Palash Kanti Kundu.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/**
 * @author Palash Kanti Kundu
 * @version 1.0
 * @since Jan 1, 2016
 */
public class OverloadingTest {

 /**
  * @param args
  */
 public static void main(String[] args) {
  printOutput("I am a string");
 }

 /**
  * Prints the line on the console.
  * 
  * @param line
  */
 public static void printOutput(String line) {
  System.out.println(line);
 }

}

Now, that's pretty fine and we can run the program and it prints the line and we can verify the output,
I am a string

Now that's cool and the methods works pretty fine for String. Now, if we have to print an integer, we can do the following,
/*
 * Copyright 2014-2016 Palash Kanti Kundu.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/**
 * @author Palash Kanti Kundu
 * @version 1.0
 * @since Jan 1, 2016
 */
public class OverloadingTest {

 /**
  * @param args
  */
 public static void main(String[] args) {
  printOutput("I am a string");
  printIntegerOutput(50);
 }

 /**
  * Prints the line on the console.
  * 
  * @param line
  */
 public static void printOutput(String line) {
  System.out.println(line);
 }

 /**
  * Prints the integer output on the console.
  * 
  * @param output
  */
 public static void printIntegerOutput(int output) {
  System.out.println(output);
 }

}

Now, this program also runs fine and we get to see the output,
I am a string
50

Pretty cool, now let's try to print some character value and we leverage our code again and add a new method,
/*
 * Copyright 2014-2016 Palash Kanti Kundu.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/**
 * @author Palash Kanti Kundu
 * @version 1.0
 * @since Jan 1, 2016
 */
public class OverloadingTest {

 /**
  * @param args
  */
 public static void main(String[] args) {
  printOutput("I am a string");
  printIntegerOutput(50);
  printCharacterOutput('c');
 }

 /**
  * Prints the line on the console.
  * 
  * @param line
  */
 public static void printOutput(String line) {
  System.out.println(line);
 }

 /**
  * Prints the integer output on the console.
  * 
  * @param output
  */
 public static void printIntegerOutput(int output) {
  System.out.println(output);
 }

 /**
  * Prints the character output on the console.
  * 
  * @param output
  */
 public static void printCharacterOutput(char output) {
  System.out.println(output);
 }

}

Well, bearable, now let's test this code,
I am a string
50
c

Perfect the output is. Now, let us extend our code to support double, float, long and boolean as well.
/*
 * Copyright 2014-2016 Palash Kanti Kundu.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/**
 * @author Palash Kanti Kundu
 * @version 1.0
 * @since Jan 1, 2016
 */
public class OverloadingTest {

 /**
  * @param args
  */
 public static void main(String[] args) {
  printOutput("I am a string");
  printIntegerOutput(50);
  printCharacterOutput('c');
  printDoubleOutput(50.0);
  printFloatOutput(25.0F);
  printLongOutput(4565L);
  printBooleanOutput(false);
 }

 /**
  * Prints the line on the console.
  * 
  * @param line
  */
 public static void printOutput(String line) {
  System.out.println(line);
 }

 /**
  * Prints the integer output on the console.
  * 
  * @param output
  */
 public static void printIntegerOutput(int output) {
  System.out.println(output);
 }

 /**
  * Prints the character output on the console.
  * 
  * @param output
  */
 public static void printCharacterOutput(char output) {
  System.out.println(output);
 }

 /**
  * Prints the double output on the console.
  * 
  * @param output
  */
 public static void printDoubleOutput(double output) {
  System.out.println(output);
 }

 /**
  * Prints the float output on the console.
  * 
  * @param output
  */
 public static void printFloatOutput(float output) {
  System.out.println(output);
 }

 /**
  * Prints the long output on the console.
  * 
  * @param output
  */
 public static void printLongOutput(long output) {
  System.out.println(output);
 }

 /**
  * Prints the boolean output on the console.
  * 
  * @param output
  */
 public static void printBooleanOutput(boolean output) {
  System.out.println(output);
 }
}

Hey, this code is confusing to work with.
Well, it is so. But we get a correct output,
I am a string
50
c
50.0
25.0
4565
false

Well, it provides correct output but what if I have to print any object ? Do, I again have to write another method ?
Well, yes. You have to. Let's try that one too. We want to print an object of class Employee. Let's check the following code,
/*
 * Copyright 2014-2015 Palash Kanti Kundu.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/**
 * @author Palash Kanti Kundu
 * @version 1.0
 * @since Dec 19, 2015
 */
public class Employee {
 /*
  * (non-Javadoc)
  * 
  * @see java.lang.Object#toString()
  */
 @Override
 public String toString() {
  return "Employee [id=" + id + ", name=" + name + ", department="
    + department + ", salary=" + salary + "]";
 }

 private String id;
 private String name;
 private int department;
 private double salary;

 /**
  * @return the id
  */
 public String getId() {
  return id;
 }

 /**
  * @param id
  *            the id to set
  */
 public void setId(String id) {
  this.id = id;
 }

 /**
  * @return the name
  */
 public String getName() {
  return name;
 }

 /**
  * @param name
  *            the name to set
  */
 public void setName(String name) {
  this.name = name;
 }

 /**
  * @return the department
  */
 public int getDepartment() {
  return department;
 }

 /**
  * @param department
  *            the department to set
  */
 public void setDepartment(int department) {
  this.department = department;
 }

 /**
  * @return the salary
  */
 public double getSalary() {
  return salary;
 }

 /**
  * @param salary
  *            the salary to set
  */
 public void setSalary(double salary) {
  this.salary = salary;
 }
}

/*
 * Copyright 2014-2016 Palash Kanti Kundu.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/**
 * @author Palash Kanti Kundu
 * @version 1.0
 * @since Jan 1, 2016
 */
public class OverloadingTest {

 /**
  * @param args
  */
 public static void main(String[] args) {
  printOutput("I am a string");
  printIntegerOutput(50);
  printCharacterOutput('c');
  printDoubleOutput(50.0);
  printFloatOutput(25.0F);
  printLongOutput(4565L);
  printBooleanOutput(false);

  Employee palash = new Employee();
  palash.setDepartment(10);
  palash.setId("" + 51531642);
  palash.setName("Palash Kanti Kundu");
  palash.setSalary(20000);

  printEmployeeOutput(palash);
 }

 /**
  * Prints the line on the console.
  * 
  * @param line
  */
 public static void printOutput(String line) {
  System.out.println(line);
 }

 /**
  * Prints the integer output on the console.
  * 
  * @param output
  */
 public static void printIntegerOutput(int output) {
  System.out.println(output);
 }

 /**
  * Prints the character output on the console.
  * 
  * @param output
  */
 public static void printCharacterOutput(char output) {
  System.out.println(output);
 }

 /**
  * Prints the double output on the console.
  * 
  * @param output
  */
 public static void printDoubleOutput(double output) {
  System.out.println(output);
 }

 /**
  * Prints the float output on the console.
  * 
  * @param output
  */
 public static void printFloatOutput(float output) {
  System.out.println(output);
 }

 /**
  * Prints the long output on the console.
  * 
  * @param output
  */
 public static void printLongOutput(long output) {
  System.out.println(output);
 }

 /**
  * Prints the boolean output on the console.
  * 
  * @param output
  */
 public static void printBooleanOutput(boolean output) {
  System.out.println(output);
 }

 /**
  * Prints the employee output on the console.
  * 
  * @param output
  */
 public static void printEmployeeOutput(Employee output) {
  System.out.println(output);
 }
}

And as for the others, this one will also print the expected output as follows,
I am a string
50
c
50.0
25.0
4565
false
Employee [id=51531642, name=Palash Kanti Kundu, department=10, salary=20000.0]

So, if I want to print n number of objects, I have to write n number of print*****Output() method ?
Isn't it insanity ?
Well, yes, if you have to deal with multiple objects, you have to write multiple methods(if you are not using Method Overloading).

Method Overloading ?
Yes, method overloading. Let's define the concept:

Method Overloading: Method Overloading a feature that allows us to have two or more different methods with the same name as long as they differ with their arguments.

OK, enough of discussion. Let's put everything in  code and let's see how Method Overloading works. For this purpose, we'll go through the same example, as we have seen earlier but with only a single method Name,  printOutput()
/*
 * Copyright 2014-2016 Palash Kanti Kundu.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/**
 * @author Palash Kanti Kundu
 * @version 1.0
 * @since Jan 1, 2016
 */
public class OverloadingTest {

 /**
  * @param args
  */
 public static void main(String[] args) {
  printOutput("I am a string");
  printOutput(50);
  printOutput('c');
  printOutput(50.0);
  printOutput(25.0F);
  printOutput(4565L);
  printOutput(false);

  Employee palash = new Employee();
  palash.setDepartment(10);
  palash.setId("" + 51531642);
  palash.setName("Palash Kanti Kundu");
  palash.setSalary(20000);

  printOutput(palash);
 }

 /**
  * Prints the line on the console.
  * 
  * @param line
  */
 public static void printOutput(String line) {
  System.out.println(line);
 }

 /**
  * Prints the integer output on the console.
  * 
  * @param output
  */
 public static void printOutput(int output) {
  System.out.println(output);
 }

 /**
  * Prints the character output on the console.
  * 
  * @param output
  */
 public static void printOutput(char output) {
  System.out.println(output);
 }

 /**
  * Prints the double output on the console.
  * 
  * @param output
  */
 public static void printOutput(double output) {
  System.out.println(output);
 }

 /**
  * Prints the float output on the console.
  * 
  * @param output
  */
 public static void printOutput(float output) {
  System.out.println(output);
 }

 /**
  * Prints the long output on the console.
  * 
  * @param output
  */
 public static void printOutput(long output) {
  System.out.println(output);
 }

 /**
  * Prints the boolean output on the console.
  * 
  * @param output
  */
 public static void printOutput(boolean output) {
  System.out.println(output);
 }

 /**
  * Prints the employee output on the console.
  * 
  * @param output
  */
 public static void printOutput(Employee output) {
  System.out.println(output);
 }
}

Wow, this code has only one method name, printOutput() and is easier to deal. But, does this work ?
Well, just clear your doubts, copy it and run the code to clear your confusion. Surely, you will get to see the following output,
I am a string
50
c
50.0
25.0
4565
false
Employee [id=51531642, name=Palash Kanti Kundu, department=10, salary=20000.0]

Yes, the same output indeed.
Well, that's the beauty of Method Overloading. In fact, if you have seen the code you'll notice that, I have only used System.out.println() to print whatever is fed to the method and I was able to do that because the println() method is overloaded to accept any kind of input and for a pretty curious reader, you can take a look here println

Its OK, if you cannot understand, what is going on there but at least you can understand that println() is also overloaded.

So, now what happens when we compile or run this code when we have a overloaded method in our class ?
At the time of compilation, compiler will resolve the invocation and try to find which version of the overloaded method should be invoked based on the passed arguments.

So, in our case,
  • printOutput("I am a string"); invokes printOutput(String line) as a String value is being passed to the method.
Similary,
  • printOutput(50); invokes printOutput(int output) as an integer is being passed as argument.
  • printOutput('c'); invokes printOutput(char output) as a character is being passed as argument
  • printOutput(50.0); invokes printOutput(double outputas a double is being passed as argument
  • printOutput(25.0F); invokes printOutput(float outputas a float is being passed as argument
  • printOutput(4565L); invokes printOutput(long outputas a long is being passed as argument
  • printOutput(false); invokes printOutput(boolean output) as a boolean is passed as argument
  • printOutput(palash); invokes printOutput(Employee output) as a Employee object is passed as argument
How do you verify ? How can I trust you ?
Don't trust me and test on your own. Well, let me leverage our example a bit more,
/*
 * Copyright 2014-2016 Palash Kanti Kundu.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/**
 * @author Palash Kanti Kundu
 * @version 1.0
 * @since Jan 1, 2016
 */
public class OverloadingTest {

 /**
  * @param args
  */
 public static void main(String[] args) {
  printOutput("I am a string");
  printOutput(50);
  printOutput('c');
  printOutput(50.0);
  printOutput(25.0F);
  printOutput(4565L);
  printOutput(false);

  Employee palash = new Employee();
  palash.setDepartment(10);
  palash.setId("" + 51531642);
  palash.setName("Palash Kanti Kundu");
  palash.setSalary(20000);

  printOutput(palash);
 }

 /**
  * Prints the line on the console.
  * 
  * @param line
  */
 public static void printOutput(String line) {
  System.out.println("String version of printOutput");
  System.out.println(line);
 }

 /**
  * Prints the integer output on the console.
  * 
  * @param output
  */
 public static void printOutput(int output) {
  System.out.println("String version of printOutput is invoked");
  System.out.println(output);
 }

 /**
  * Prints the character output on the console.
  * 
  * @param output
  */
 public static void printOutput(char output) {
  System.out.println("char version of printOutput is invoked");
  System.out.println(output);
 }

 /**
  * Prints the double output on the console.
  * 
  * @param output
  */
 public static void printOutput(double output) {
  System.out.println("double version of printOutput is invoked");
  System.out.println(output);
 }

 /**
  * Prints the float output on the console.
  * 
  * @param output
  */
 public static void printOutput(float output) {
  System.out.println("float version of printOutput is invoked");
  System.out.println(output);
 }

 /**
  * Prints the long output on the console.
  * 
  * @param output
  */
 public static void printOutput(long output) {
  System.out.println("long version of printOutput is invoked");
  System.out.println(output);
 }

 /**
  * Prints the boolean output on the console.
  * 
  * @param output
  */
 public static void printOutput(boolean output) {
  System.out.println("boolean version of printOutput is invoked");
  System.out.println(output);
 }

 /**
  * Prints the employee output on the console.
  * 
  * @param output
  */
 public static void printOutput(Employee output) {
  System.out.println("Employee version of printOutput is invoked");
  System.out.println(output);
 }
}


Now, see the output and you will surely believe me,
String version of printOutput
I am a string
String version of printOutput is invoked
50
char version of printOutput is invoked
c
double version of printOutput is invoked
50.0
float version of printOutput is invoked
25.0
long version of printOutput is invoked
4565
boolean version of printOutput is invoked
false
Employee version of printOutput is invoked
Employee [id=51531642, name=Palash Kanti Kundu, department=10, salary=20000.0]

So, you are clear now, that particular version of method was invoked based on the argument.

OK, let's now see the rules of method overloading,

Rule - 1: The obvious rule, you have understood by now. Arguments should differ for different methods.
What do I mean by that is, you cannot have two methods with same name and same argument list. So, the following is invalid,
/*
 * Copyright 2014-2016 Palash Kanti Kundu.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/**
 * @author Palash Kanti Kundu
 * @version 1.0
 * @since Jan 1, 2016
 */
public class OverloadingTest {

 /**
  * @param args
  */
 public static void main(String[] args) {
  printOutput("I am a string");
 }

 /**
  * Prints the line on the console.
  * 
  * @param line
  */
 public static void printOutput(String line) {
  System.out.println("String version of printOutput");
  System.out.println(line);
 }

 /**
  * Prints the line on the console.
  * 
  * @param line
  */
 public static void printOutput(String myLine) {
  System.out.println("String version 2 of printOutput");
  System.out.println(myLine);
 }
}

The reason is simple, while compiling, compiler will not understand which method to be invoked. As you can see that two method can work pretty different way. So choosing which one is right is almost next to impossible for Java. Remember from this article, your computer is a slave and it cannot decide what to do until and unless you are asking it to do specifically. So, the compiler cannot decide which method to invoke. So the preceding is invalid.

Rule - 2: If you have two methods with different return types but same arguments, you cannot overload them. So, two methods with different return type but same argument list cannot be overloaded. So, the following is invalid,
/*
 * Copyright 2014-2016 Palash Kanti Kundu.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/**
 * @author Palash Kanti Kundu
 * @version 1.0
 * @since Jan 1, 2016
 */
public class OverloadingTest {

 /**
  * @param args
  */
 public static void main(String[] args) {
  printOutput("I am a string");
 }

 /**
  * Prints the line on the console.
  * 
  * @param line
  */
 public static void printOutput(String line) {
  System.out.println("String version of printOutput");
  System.out.println(line);
 }

 /**
  * Prints the line on the console.
  * 
  * @param line
  */
 public static String printOutput(String myLine) {
  System.out.println("String version 3 of printOutput");
  System.out.println(myLine);
  return myLine;
 }
}

The reason is simple, although you have a return type of a method, you can simply call the method without capturing the output of the method.

For a moment, take the example of the preceding, which version of the method will be invoked ?
The void return type version or the String return type version ?
Again, it is confusing and thus invalid.

There is another rule regarding Method Overloading and we won't be covering this here, as we have not gone through the topic yet. But for completeness, I am mentioning another rule here. We'll discuss this later,

Rule - 3: Exceptions are not part of method signature. So, overloaded methods can have any exceptions thrown. For example, the following is completely valid,
/*
 * Copyright 2014-2016 Palash Kanti Kundu.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/**
 * @author Palash Kanti Kundu
 * @version 1.0
 * @since Jan 1, 2016
 */
public class OverloadingTest {

 /**
  * @param args
  * @throws IOException
  */
 public static void main(String[] args) throws IOException {
  printOutput("I am a string");
  printOutput("String 1", "String 2");
 }

 /**
  * Prints the line on the console.
  * 
  * @param line
  */
 public static void printOutput(String line) throws IOException {
  System.out.println("String version of printOutput");
  System.out.println(line);
 }

 /**
  * Prints the line on the console.
  * 
  * @param line
  */
 public static void printOutput(String line, String line2)
   throws RuntimeException {
  System.out.println(line);
  System.out.println(line2);
 }
}

And following is the output,

String version of printOutput
I am a string
String 1
String 2

It's OK if you could not understand what is going on for rule 3, we'll discuss them later.
Hope, you are clear with Method Overloading or Compile Time Polymorphism.

No comments:

Post a Comment