[SCJP Tips] [SCJP Tips: Overloading, Overriding, Runtime Type and Object Orientation] [SCJP Tips: Language Fundamentals] Selecting the Most Specific Method
I've seen many people stumble over how Java chooses the method to be invoked based on an invocation. I've had trouble understanding this from time to time, myself. Take a look at the following sample question and see if you can determine the correct answer.
public class Test
{
public static void doIt(int a, long b, long c)
{
System.out.println("In doIt(int, long, long)");
}
public static void doIt(int a, int b, long c)
{
System.out.println("In doIt(int, int, long)");
}
public static void main(String[] args)
{
doIt(1, 2, 3);
}
}
What is the result of compiling and executing the above code?
A. Prints "In doIt(int, long, long)"
B. Prints "In doIt(int, int, long)"
C. Compiler Error
D. Run-Time Error
|
So, what was your answer? If you said B, you're right. If you don't believe me, try it for yourself. This code prints "In doIt(int, int, long)". Let's look at why the other answers are wrong, shall we?
Let's start with answer A. Why don't we end up in the first version of doIt, that takes one int and two longs? Well, the reason for that is because, when the compiler tries to determine which method to invoke, it chooses the "most specific method." In general terms, if the parameters of Method A are valid in Method B, but not vice versa, Method A is said to be "more specific" than Method B. In this case, that's exactly what we have. We are passing three ints to our doIt method so the compiler looks for the most specific applicable method. In this case, we have two applicable methods, but which is most specific? Well, since any invocation of doIt(int, long, long) would also work for doIt(int, int, long) but not the other way around, the method doIt(int, int, long) is deemed to be the "most specific method."
If we had used this line to invoke our method:
doIt(1, Long.MAX_VALUE, 3);
We'd have ended up with the output "In doIt(int, long, long)". Why? Well, that's because, in this case, we only have one applicable method. We can't send (int, long, int) to a method that accepts (int, int, long) but we can send it to a method that accepts (int, long, long). Therefore, we only have one applicable method and the first method would be invoked.
So what about answers C and D? Well, C is incorrect because, as we saw, the compiler had no problem determining which method to invoke. As for D, there's really no chance of a run-time exception occurring in this application.
So, with that one down, let's try one more sample question.
public class Test
{
public static void doIt(int a, long b, long c)
{
System.out.println("In doIt(int, long, long)");
}
public static void doIt(long a, int b, int c)
{
System.out.println("In doIt(long, int, int)");
}
public static void main(String[] args)
{
doIt(1, 2, 3);
}
}
What is the result of compiling and executing the above code?
A. Prints "In doIt(int, long, long)"
B. Prints "In doIt(long, int, int)"
C. Compiler Error
D. Run-Time Error
|
So what did you answer this time? A? B? If you did, you're wrong. In this case, the answer is C. This code produces a compile time error.
So why is it that this code produces a compile time error while the previous code did not? The problem here is that our method invocation is ambiguous. The compiler can not determine which method to invoke so it, in essence, throws up its arms and yells.
What is it that gives the compiler so much trouble with this pair of methods? The problem here is that the compiler can not determine which one is "more specific." In our first example, every parameter list you sent to the second method was valid for the first, but not the other way around. That made the second method "more specific." In this case, however, you can find a set of parameters that is valid for the first method but not for the second AND you can find a set of parameters for the second method that is not valid for the first. This causes the compiler to go into horrible convulsions and die a slow, miserable death. (Okay, so it's not that gruesome, but you get the idea.)
Hopefully, that gives you a good understanding of how Java determines the "most specific method." Normally, I see questions like these asked with objects, not primitives, but the same concepts hold. This blog entry was actually inspired by a thread I spotted on the Ranch (here). You can also read all about the nitty gritty details by checking out the JLS, §15.12.2.2 Choose the Most Specific Method.
Until next time,
Corey
Your choice B does not match the method of the last example. Bad cut-paste job.
Good catch. It's fixed now - thanks.
Shouldn't method A be "more specific" than method B.
Shouldn't method A be "more specific" than method B.
Yup. Good catch - I've fixed the typo.
