Reusing the same method name in the same class or subclass but with different arguments (and optionally, a different return type) is called Method Overloading in Java.
There are certain rules for overloading, the below code points out all of the rules:
In short, the only rule you MUST obey is to change the argument list of the overloaded method, the rest are all optional.
Invoking Overloaded Methods
The output of the above program is:
In the Animal version In the Horse version In the Animal version
Notice the call
doStuff(animalRefToHorse), here the
Animal version of
doStuff() is called despite the actual
object being passed is of a
Horse. The reference type (not the object type) determines which overloaded method is
To summarize, which overridden version of the method to call (in other words, from which class in the inheritance tree) is decided at runtime based on object type, but which overloaded version of the method to call is based on the reference type of the argument passed at compile time.
Therefore, polymorphism doesn’t determine which overloaded version is called, polymorphism does come into play when the decision is about which overridden version of a method is called.
The confounding part in method overloading
I will show you different scenarios after which you can answer any question related to method matching (which method will be invoked).
The 3 factors that can make overloading a little tricky (written in order of preference):
The output of the above program is
float float float float int,int Long,Long.
From the output it is clear that the JVM prefers widening over autoboxing and var-args. In every case, when an exact match isn’t found, the JVM uses the method with the smallest argument that is wider than the parameter.
Now look at the call
go(l, l) at last, this invokes
go(Long x, Long y) rather than
go(long... x) which clearly shows
JVM prefers boxing over var-args.
Widening reference variables
Reference widening depends on inheritance, in other words if it passes the IS-A test then no harm. Consider the below code:
The above code compiles fine as
Dog can widen into an
Animal because it passes the IS-A test. If in case,
didn’t have extended
Animal then widening wouldn’t be possible and the code wouldn’t compile.
Similarly, you cannot widen
Long but you can widen
Combine Widening with Boxing
Let’s see what happens when the compiler has to widen and then autobox the parameter for a match to be made.
The above program fails to compile, the JVM does not widen and then box. It may be because widening existed in the earlier versions of Java and it wanted a method that is invoked via widening shouldn’t lose out to a newly created method that relies on boxing. In other words, Java designers wanted the preexisting code should function the way it used to.
Now imagine if JVM tried to box first, the
byte would have been converted to a
Byte. Now we’re back to trying to widen a
Byte to a
Long, and of course, the IS-A test fails.
So both of the ways didn’t work.
Now let’s see another program when the compiler has to autobox and then widen the parameter for a proper match.
The above code compiles and produces the output
5. Firstly, the
byte b was boxed to a
Byte. And then the
reference was widened to an
Object). So, the
go() method got an
that actually refers to a
From the above 2 examples its certain that the JVM can never widen and then box but can box and then widen.
Combine both Widening and Boxing with Var-args
The above code compiles fine and produces the output:
long... Integer... Object...
From the result, its clear that we can successfully combine var-args with either widening or boxing.
Q1. Consider the below program in which a method is both overridden and overloaded.
Figure out which version of
eat() will run on each of the invocation made?
A. Animal ah = new Horse(); ah.eat(); B. Horse he = new Horse(); he.eat("Apples"); C. Animal a2 = new Animal(); a2.eat("treats"); D. Animal ah2 = new Horse(); ah2.eat("Carrots");