Method overloading allows you to begin to practice
polymorphism.
Polymorphism is having consistent behaviour between classes
and objects that is appropriate. For example, think of the
verb "open". You can go to your laptop and "open" it by
lifting the lid. You can walk up to a door and "open" it by
turning the handle and pushing or pulling it.
You can go into a bank and "open" a bank account by providing
personal information and some money to deposit.
You can apply the verb "open" to many different kinds of objects,
yet you always know how to "open" each object in the way
it needs. The "open" action is performed in an appropriate
way on several very different objects.
In programming, one way you can practice polymorphism
is to create overloaded methods:
methods that have the same name, but might perform
in a different way depending on the type of arguments
they receive and possibly even the type of data they
return. The differences between these methods may be
small, or they may be large.
For example, in using some of the existing classes in Java, you might have
noticed that in the documentation, some classes have
multiple versions of methods with the same name.
For example, the Math class has four different versions of
the max() method: one for two doubles, one for two
floats, one for two ints, and one
for two longs.
Therefore, the Math.max() method is overloaded: each
version operates on different kinds of numbers.
Similarly, there are multiple
versions of the println() method. One version
takes a string value, one version takes an integer value, and one
version even takes a double value. That's why all
of these statements work:
In this lesson you'll learn how to create overloaded
methods correctly and how they work.
Pre-Requisites
Before doing this lesson, make sure you understand
how to create and use your own methods.
How to Create Overloaded Methods
To create overloaded methods, you simply declare
more than one method with the same name and different
parameter lists. The method names must all be the same
and the parameter lists must be different.
For example, the following two method headers define a set of
overloaded methods called calculatePay():
public double calculatePay(int deptNum) { ... }
public double calculatePay(double hours, double rate) { ... }
When you invoke the calculatePay() method, Java will locate the
correct method to execute based on the parameter list.
So if you were to call the calculatePay() with the statement:
double pay = calculatePay(8.5, 24.50);
..then Java would locate the calculatePay() method that had two
double parameter variables.
If you were to execute the statement:
double pay = calculatePay(2);
..then Java would locate the calculatePay() method that had one
int parameter variable (or one
double, since an int can be
implicitly cast into a double).
If you were to try the statement:
double pay = calculatePay("Sales Department");
Then you would receive an error that the method
calculatePay(java.lang.String) didn't exist: there is no
calculatePay() method that takes a String.
You have to be careful to avoid
ambiguous invocation
when defining overloaded methods.
Ambiguous invocation occurs when you invoke a method but
there is more than one match for it.
For example, the following overloaded methods would not
be valid:
public static String findCustomer(String firstName) { ... }
public static String findCustomer(String lastName) { ... }
In the above example, Java sees two findCustomer() methods
with a String parameter.
The name of the parameter is irrelevant; Java sees
these two method definitions as being exactly the same.
In general, you can overload methods as long as the parameter
list is different. You can also change the return types,
but again, only if the parameter lists are different. Therefore
these methods are valid:
public static int getValidNumber(String prompt, int min, int max) { ... }
public static double getValidNumber(String prompt, double max) { ... }
These are valid because the parameter list differs between the
two. However, the methods below are not valid because
even though the return types are different, the parameter lists are
the same:
public static int getValidNumber(String prompt, int min, int max) { ... }
public static double getValidNumber(String prompt, int min, int max) { ... }
So in summary, when creating overloaded methods, make sure that:
The method names are the same.
The parameter lists are of different.
As long as Rule #2 applies, it's ok to have different return types.
Exercise
1. What is wrong with the following program?
public class Overloading {
public static void main(String[] args) {
doStuff("Sydney");
doStuff("Sydney", 5);
}
public static void doStuff(String message) {
System.out.println(message);
}
public static void doStuff(String message, int num) {
for (int i=1; i<=num; i++)
System.out.println(message);
}
public static boolean doStuff(String name) {
return name.equalsIgnoreCase("kaluha")
}
}
Ambiguous Invocation for the first and third doStuff()
method: both accept a single String argument, so Java doesn't
know which one to execute when you call doStuff("Sydney").
How Method Overloading Works
When you have multiple versions of the same
method, how does Java know which method to use? It will
always look for the best match. For example, imagine
you had the following code segment:
int n1 = 5;
int n2 = 10;
double n3 = 1.0;
double n4 = 3.33;
System.out.println(Math.max(n1, n2));
System.out.println(Math.max(n3, n4));
In line 7, the max() method recieves 2 integers, therefore the
integer version will execute. In line 8, the max() method receives
two doubles, so the double version will execute.
But what happens when you have two different types?
System.out.println(Math.max(n1, n3));
In the above example, we're passing one integer value and one double
value. So will the 2-integers version execute or the 2-doubles
version execute? If you were to execute that line of code,
you would see that it outputs 5.0: n1 is 5 and n3 is
1.0, and the largest of those 2 is 5. The output showing a floating
point literal tells you that the double version of Math.max()
was executed. Why? Let's try a different example to understand
the answer to that question.
public class OverloadingExample1 {
public static void main(String[] args) throws Exception {
int n1 = 5;
int n2 = 10;
double n3 = 1.0;
double n4 = 3.33;
// which one executes?
method(n1, n2);
method(n3, n4);
method(n2, n4);
method(n3, n2);
}
public static void method(int a, int b) {
System.out.println("I take two integers.");
}
public static void method(double a, double b) {
System.out.println("I take two doubles");
}
public static void method(int a, double b) {
System.out.println("I take one int and one double.");
}
}
Run the program and look at your output:
I take two integers.
I take two doubles
I take one int and one double.
I take two doubles
It should be obvious why the first two lines of output appear:
the statement on line 10 executes method(int, int) because it
receives the two integer arguments, and the statement on line 11
executes method(double, double) because it receives two double
arguments. The statement on line 12 calls method() with one
int and one double, which exactly matches the method(int, double)
method. But what about the statement on line 13?
Line 13 calls method(n3, n2) - n3 is a double and n2 is an integer.
But there is no method(double, int) at all. In this case, Java will
try for the best match.
It won't match method(int, int) or method(int, double)
because it can't accept the
double as the first argument. However,
method(double, double) matches because the second int
argument can be implicitly cast into a double.
Therefore, the method(double, double) executes, which results
in the fourth line of output.
Java will always choose the best match by matching up
argument and parameter data types, performing implicit casting
if necessary.
Knowing this, it confirms that Math.max(double, double)
was executed since max(int, int), max(long, long), and
max(float, float) can't match, but the first int
argument can be cast into a double value for
max(double, double).
Exercise
For each statement, identify which version of the
overloaded methods will execute.
// version 1
public static void printThings(String str1, String str2) {
System.out.printf("%s and %s\n", str1, str2);
}
// version 2
public static void printThings(int num1, double num2) {
System.out.printf("%d and %f\n", num1, num2);
}
// version 3
public static void printThings(int num1, int num2) {
System.out.printf("%d and %d\n", num1, num2);
}
// version 4
public static void printThings(String str1, double num1) {
System.out.printf("%s and %f\n", str1, num1);
}
printThings("hello", "world"); executes version 1
of printThings() because it takes 2 string arguments.
printThings("hello", 1); executes version 4, which
accepts a string argument and a double argument - the int argument
is implicitly cast into a double so that it can be passed to the
method.
printThings(5, 10); executes version 3 of
printThings(), because it takes 2 integer arguments.
printThings(5, 10.0); executes version 2 of
printThings(), because it takes one integer and one double argument.
printThings(1.0, 1.5); doesn't match any of the
methods: there is none that is capable of accepting two double values
as arguments. This would appear in your code as an error that it
"is not applicable for the arguments (double, double)".
Exercise
A program calculates and displays bonus amounts
to pay various types of employees. There are 3 separate
departments, numbered 1, 2, and 3. Department 1 employees are
paid a bonus based on their sales: If their sales
amount is over $5000 they get 5% of those sales, otherwise they
get nothing. Department 2 employees are paid a bonus
based on the number of units they sell: They get $20 per unit
sold, and an extra $10 per unit if they sell 25 units or more;
if they sell no units, they get nothing. Department 3
employees assemble parts in the plant and are paid a
bonus of 10 cents per part if they reach a certain level:
Part-time employees must assemble more than 250 parts to get
the 10-cent-per-part bonus, and full-time employees must assemble
more than 700.
Write a set of 3 overloaded methods called getBonus() that
works with the program below, according to the
specifications described above.
public final static int UNITS_PT = 250;
public final static int UNITS_FT = 700;
public final static double SALES_BONUS = 5000.0;
public final static double SALES_BONUS_RATE = 0.05;
public final static double SALES_UNIT_REG = 20.0;
public final static double SALES_UNIT_EXTRA = 10.0;
public final static int SALES_UNIT_BONUS = 25;
public final static double PARTS_BONUS = 0.1;
public static void main(String[] args) {
Scanner keysIn = new Scanner(System.in);
System.out.println("Enter department: ");
int dept = keysIn.nextInt();
double bonus = 0;
switch (dept) {
case 1:
System.out.print("Enter sales: ");
double sales = keysIn.nextDouble();
bonus = getBonus(sales);
break;
case 2:
System.out.print("Enter number of units sold: ");
int numUnits = keysIn.nextInt();
bonus = getBonus(numUnits);
break;
case 3:
System.out.print("Enter # of pieces completed: ");
int pieces = keysIn.nextInt();
System.out.print("Full-time (1) or Part-Time (2)? ");
int empType = keysIn.nextInt();
int bonusLimit = (empType == 1) ? UNITS_FT : UNITS_PT;
bonus = getBonus(pieces, bonusLimit);
break;
default:
System.out.print("Error! ");
}
System.out.printf("Bonus Amount: $%.2f%n", bonus);
}