Overloading
Methods
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. 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 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 number of their
parameters. While overloaded methods may have different return types, the
return type alone is insufficient to distinguish two versions of a method. When
Java encounters a call to an overloaded method, it simply executes the version
of the method whose parameters match the arguments used in the call.
Here is a simple example that
illustrates method overloading:
// 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;
}
}
class Overload {
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);
}
}
This program generates the
following 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.
When an overloaded method is
called, Java looks for a match between the arguments used to call the method
and the method’s parameters. However, this match need not always be exact. In
some cases, Java’s automatic type conversions can play a role in overload
resolution. For example, consider the following program:
// Automatic type conversions apply to overloading.
class OverloadDemo {
void test() {
System.out.println("No parameters");
}
// 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
void test(double a) {
System.out.println("Inside test(double) a:
" + a);
}
}
class Overload {
public static void
main(String args[]) { OverloadDemo ob = new OverloadDemo(); int i = 88;
ob.test(); ob.test(10, 20);
ob.test(i); // this will
invoke test(double) ob.test(123.2); // this will invoke test(double)
}
}
This program generates the
following output:
No parameters a and b: 10 20
Inside test(double) a: 88
Inside test(double) a: 123.2
As you can see, this version
of OverloadDemo does not define test(int). Therefore, when test( ) is called with an integer
argument inside Overload, no
matching method is found. However, Java can automatically convert an integer
into a double, and this conversion
can be used to resolve the call. Therefore, after test(int) is not found, Java elevates i to double and then
calls test(double). Of course, if test(int) had been defined, it would
have been called instead. Java will employ its automatic type conversions only
if no exact match is found.
Method
overloading supports polymorphism because it is one way that Java implements
the “one interface, multiple methods” paradigm. To understand how, consider the
following. In languages that do not support method overloading, each method
must be given a unique name. However, frequently you will want to implement
essentially the same method for different types of data. Consider the absolute
value function. In languages that do not support overloading, there are usually
three or more versions of this function, each with a slightly different name.
For instance, in C, the function abs( )
returns the absolute value of an integer, labs(
) returns the absolute value of a long integer, and fabs( ) returns the absolute value of a floating-point value. Since
C does not support overloading, each function has its own name, even though all
three functions do essentially the same thing. This makes the situation more
complex, conceptually, than it actually is. Although the underlying concept of
each function is the same, you still have three names to remember. This
situation does not occur in Java, because each absolute value method can use
the same name. Indeed, Java’s standard class library includes an absolute value
method, called abs( ). This method
is overloaded by Java’s Math class
to handle all numeric types. Java determines which version of abs( ) to call based upon the type of
argument.
The
value of overloading is that it allows related methods to be accessed by use of
a common name. Thus, the name abs
represents the general action that is
being performed. It is left to the compiler to choose the right specific version for a particular
circumstance. You, the programmer, need only remember the general operation
being performed. Through the application of polymorphism, several names have
been reduced to one. Although this example is fairly simple, if you expand the
concept, you can see how overloading can help you manage greater complexity.
When you overload a method,
each version of that method can perform any activity you desire. There is no
rule stating that overloaded methods must relate to one another. However, from
a stylistic point of view, method overloading implies a relationship. Thus,
while you can use the same name to overload unrelated methods, you should not.
For example, you could use the name sqr
to create methods that return the square
of an integer and the square root of
a floating-point value. But these two operations are fundamentally different. Applying method overloading in this
manner defeats its original purpose. In practice, you should only overload
closely related operations.
Overloading
Constructors
In
addition to overloading normal methods, you can also overload constructor
methods. In fact, for most real-world classes that you create, overloaded
constructors will be the norm, not the exception. To understand why, let’s
return to the Box class developed in
the preceding chapter. Following is the latest version of Box:
class Box { double width; double height; double
depth;
This is the constructor for Box. Box(double w,
double h, double d) {
width = w; height = h; depth = d;
}
compute and return volume double volume() {
return width * height * depth;
}
}
As you can see, the Box( ) constructor requires three
parameters. This means that all declarations of Box objects must pass three arguments to the Box( ) constructor. For example, the following statement is
currently invalid:
Box ob = new Box();
Since Box( ) requires three arguments, it’s an error to call it without
them. This raises some important questions. What if you simply wanted a box and
did not care (or know) what its initial dimensions were? Or, what if you want
to be able to initialize a cube by specifying only one value that would be used
for all three dimensions? As the Box
class is currently written, these other options are not available to you.
Fortunately, the solution to
these problems is quite easy: simply overload the Box constructor so that it handles the situations just described.
Here is a program that contains an improved version of Box that does just that:
/* Here,
Box defines three constructors to initialize the dimensions of a box various
ways.
*/
class Box { double width; double height; double
depth;
constructor used when all dimensions specified
Box(double w, double h, double d) {
width = w; height = h; depth
= d;
}
constructor used when no dimensions specified
Box() {
width = -1; // use -1 to
indicate height = -1; // an uninitialized
depth = -1; // box
}
constructor used when cube is created
Box(double len) {
width = height = depth = len;
}
compute and return volume
double volume() {
return width * height * depth;
}
}
class OverloadCons {
public static void main(String args[]) {
// create boxes using the various constructors
Box mybox1 = new Box(10, 20, 15);
Box mybox2 = new Box(); Box
mycube = new Box(7);
double vol;
get volume of first box vol = mybox1.volume();
System.out.println("Volume of mybox1 is
" + vol);
get volume of second box
vol = mybox2.volume();
System.out.println("Volume of mybox2 is " + vol);
// get volume of cube
vol =
mycube.volume();
System.out.println("Volume of mycube is
" + vol);
}
}
The output produced by this
program is shown here:
Volume of mybox1 is 3000.0
Volume of mybox2 is -1.0
Volume of mycube is 343.0
As you
can see, the proper overloaded constructor is called based upon the parameters
specified when new is executed.
Related Topics
Privacy Policy, Terms and Conditions, DMCA Policy and Compliant
Copyright © 2018-2023 BrainKart.com; All Rights Reserved. Developed by Therithal info, Chennai.