Hello friends Please consider the following 2 examples (they are simplied form of Dan's Chapter 6/Exam 1, Q17 and Q20 respectively):
This will print: B
This will print: A In the first example, m1 is overridden and in the second, it's overloaded. Is it true that the method which gets invoked at run-time depends upon whether it's overridden or overloaded? If yes, it would surprising because this distinction is 'not' mentioned in the Khalid Mughal book, which I rate very highly. Thanks Harwinder [ October 21, 2003: Message edited by: Harwinder Bhatia ]
Keep in mind that overloading and overriding really have nothing to do with one another. They are not mere variations on the same thing - they are totally different. Overloading in the practice of using the same method name with multiple differing signatures. This, in effect, produces multiple unique methods as each signature is different. Overriding, on the other hand, uses the EXACT SAME method signature repeatedly in order to achieve dynamic behavior of objects. In your first example (which has a typo on the method signature, I believe), you have overriddent the method m1 by using an identical method signature in the subclass. Doing so causes the JVM to utilize dynamic method binding and results in the method m1 to be executed in the subclass (which is the run-time type of the variable), rather than the parent class. In the second example, we are overloading, not overriding. Therefore, as the method m1 is not overridden, there is absolutely no reason for the JVM to use dynamic method binding. Instead, it goes right to the compile-time type of the variable (as opposed to the run-time type used above), which is A, and invokes the proper method. I hope that helps.
When you override a method, you replace the method with an implementation in the subclass. When you overload a method, you create a new method with the same name as a method that already exists, but with a different argument list. In the second example, s/b . So the next line [code]b1.m1(b2);[code] invokes the original method instead of the overloaded method, because the original method takes a type A as an argument. To put it in another way, in the first example, type B has a single method which we could call 'void B.m1()'. In the second example, type B has two methods, which we would call 'void B.m1( A)' and 'void B.m1( B)'. Since the two methods have the same name, the compiler chooses which method to invoke by the types and numbers of the arguments.
Thanks Doug & Corey for the express replies. There was indeed a typo, which I just corrected (there is no m2). I compiled the examples again and verified the results. Corey, I am pretty clear on the first example (I think I am), but the second one seems contradictory. I understand the distinction between the 2 cases very clearly but what I don't understand is the "why" this distinction is in place. If method m1 is overloaded in the subclass and a call b1.m1(b2) is made, the argument type should determine which version of the overloaded method should get invoked. At run-time, b1 is essentially a reference to class B object anyways. When "Dynamic Method Invocation" is applied in the first case, why isn't it applied in the second? What is the rationale behind it? Thanks Harwinder
When "Dynamic Method Invocation" is applied in the first case, why isn't it applied in the second? What is the rationale behind it?
It isn't applied in the second case because there is no reason to apply it. Dynamic method invocation is only used when a method is overridden. In the second example, there is no overridden method. Therefore, dynamic method invocation is not used. Let's take a look at that example and see what we really have going on.
In this case, we have creates two new objects. Both of these objects have a run-time type of B, but b1 has a compile-time type of A while b2 has a compile-time type of B. Now, if we remember what we have done with our methods, we'll see something that is teh key to this whole thing. Notice that, in class A, we have this method signature:
While, in class B, we have this method signature:
So, what does that mean? Well, class B extends class A. Therefore, class B inherits the method m1(A) from class A. However, class B overloads that method (it DOES NOT override it). The result is that class A has one method named m1 while class B has two methods named m1. When you compile this, the compiler is going to try to determine which method should be invoked. It starts by looking at the type of the variable on which the method is being invoked. The compile-time type of b1 is A, so the compiler looks into the definition of the class A to find a suitable method. It finds one (and only one as the overloaded method is in B, not A). It then checks to see if that method is overridden. It is not, so this is the appropriate method to invoke. I hope that makes this a bit clearer for you. If you really want to get to the gritty details of this, check out the JLS: §15.12 Method Invocation Expressions.
Hi Corey Thanks for your elaborate response. It does make things a lot clearer. As I said, I understand how method invocation works. I followed the link which you gave and read through some part of the JLS too.
It isn't applied in the second case because there is no reason to apply it.
Well, I have been thinking of a "reason" and I think I have one (I'm just thinking out loud here). In case a subclass overloads a method in the superclass, why doesn't Java language adopt the policy of "closest match", like it is the case in resolving overloaded methods in the same class, especially when the runtime type of the object is the subclass type anyways? Wouldn't it have made things more logical and consistent in 2 ways: 1. Always apply dynamic method invocation 2. and in case a superclass method is overloaded by subclass, always try to find the closest match. Thanks Harwinder