• Post Reply Bookmark Topic Watch Topic
  • New Topic
programming forums Java Mobile Certification Databases Caching Books Engineering Micro Controllers OS Languages Paradigms IDEs Build Tools Frameworks Application Servers Open Source This Site Careers Other Pie Elite all forums
this forum made possible by our volunteer staff, including ...
Marshals:
  • Campbell Ritchie
  • Jeanne Boyarsky
  • Ron McLeod
  • Paul Clapham
  • Liutauras Vilda
Sheriffs:
  • paul wheaton
  • Rob Spoor
  • Devaka Cooray
Saloon Keepers:
  • Stephan van Hulst
  • Tim Holloway
  • Carey Brown
  • Frits Walraven
  • Tim Moores
Bartenders:
  • Mikalai Zaikin

Mock exam question

 
Ranch Hand
Posts: 31
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
A Dan Chisholm mock exam question:
Consider the code:
class A {
void m1(A a) {System.out.print("A");}
}
class B extends A {
void m1(B b) {System.out.print("B");}
}
class C extends B {
void m1(C c) {System.out.print("C");}
}
class D {
public static void main(String[] args) {
A c1 = new C();
C c2 = new C();
c1.m1(c2);
}
}

I would have thought that the output from this should be "C" but it is "A". My thinking is that the instance type of c1 is C and the reference type of c2 is C so the m1 method on C would be the one invoked. What am I not getting?
Thanks!
 
Ranch Hand
Posts: 178
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
The output is 'A' since method m1() in class B and class C are not overridden, note they do not take the same parameter of class A ... therefore no polymorphic behaviour!
 
Lisa French
Ranch Hand
Posts: 31
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Ok, so if there is no overriding going on, then the reference variable type (in this case "A") determines what method is actually invoked?
So, even though the instance c1 is of type "C" and the argument type is "C", since the type of c1 is "A", it is the m1 on A that takes an argument of type A - void M1(Aa) - that is invoked.
[ June 28, 2003: Message edited by: Lisa F. ]
 
Lisa French
Ranch Hand
Posts: 31
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Does anyone have any more insights into this one?
Thanks!
 
Ranch Hand
Posts: 1090
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Hi Lisa
Think it from the point of inheritance. Class C has void m1(A a), void m1(B b) and void m1(C c). Now when you say c1.m1(c2). What really happenes is that method which C has inherited from A gets executed. Why? Why not void m1(C c). Now the methods are overloaded. You can think of overloaded methods as simply methods having the same name. I guess it wouldn't had caused much confusion if the method in class C was named something like classCmeth(). Now when you execute c1.m1(c2); A has no idea whether there exists a method in class C that will take in a parameter of class C type. So it would report an error as no such method found. But C happens to be a subclass of A and because of that A can take any class C type of object. Now when void m1(A a) gets an input of class C type its something like this m1(A c). This is why the output is A. Here, had the method name in class C been aVeryLongNameMethodInClassC() it would had made no difference in the output for this piece of code.
 
Lisa French
Ranch Hand
Posts: 31
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Ok, if I change the code to:
class A {
void m1(int a) {System.out.println("A");}
}
class B extends A {
void m1(int b) {System.out.println("B");}
}
class C extends B {
void m1(int c) {System.out.println("C");}
}
class D2 {
public static void main(String[] args) {
A c1 = new C();
c1.m1(5);
}
}
The output is "C" as I would expect. Why does changing the parameter type make this difference?
 
Lisa French
Ranch Hand
Posts: 31
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
My further thinking:
As Anupam said above "Class C has void m1(A a), void m1(B b) and void m1(C c)." m1(B b) was inherited from B and m1(A a) was inherited from B inherited from A. So C has these three methods overloaded with 3 different parameter types.
So when m1 is called on an object of type C passing an argument of type C, I would think that the method on class C that takes an argument of type C would be executed. But the one that takes an argument of type A is the one executed.
Am I really thick or is this a difficult concept to grasp? The one above with the primitive data type parameter makes perfect sense to me. I'm guessing that the different parameter types which inherit from each other is where I'm losing it.
 
Ranch Hand
Posts: 1561
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Originally posted by Lisa F.:
Ok, if I change the code to:
class A {
void m1(int a) {System.out.println("A");}
}
class B extends A {
void m1(int b) {System.out.println("B");}
}
class C extends B {
void m1(int c) {System.out.println("C");}
}
class D2 {
public static void main(String[] args) {
A c1 = new C();
c1.m1(5);
}
}
The output is "C" as I would expect. Why does changing the parameter type make this difference?


Hi Lisa. Now you're overriding, not overloading
;). The arguments for all the methods are the same, as well as the return type and method name, of course.
So, when you see that's overriding, the method invoked is based on the new object type.
A c1 = new C();
when you see an overloading, like the very first post, it's the reference type you've gotta look at
A c1 = new C();
hope this helps
 
Lisa French
Ranch Hand
Posts: 31
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Kathy's book says that the overloaded method executed is determined by the type of the arguments. It does NOT say that the type of the object reference on which the method is called is a determining factor; but it doesn't say it isn't either. This is why I thought the method on class C would be the one executed. It is the one with the defined parameter type the same as the argument type. But from what I'm reading here, it appears that the type of the object on which the method is called contributes.
Is this right?
 
Andres Gonzalez
Ranch Hand
Posts: 1561
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Well, I'm also studying with the KnB book but from what I remember (I don't have the book here) is that the reference type (not the object type) determines which overloaded method is invoked. "A" in my example.
Overriden methods are resolved at runtime based on the object type. "C" in my example.
If that's not true please let me know ASAP so I can delay my exam date straight !
[ June 30, 2003: Message edited by: Andres Gonzalez ]
 
Andres Gonzalez
Ranch Hand
Posts: 1561
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
from Dan's answer


Even though c1 is an instance of class C, the reference type is A so the overloaded methods declared in the subclasses are not accessible. For that reason, the implementation of method m1 declared in class A is invoked.

 
Sheriff
Posts: 5782
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Lisa,
Thanks for joining JavaRanch.
Unfortunately your name violates our naming policy. Please take a quick look at the rules and edit your profile accordingly.
Thank you!
 
Lisa French
Ranch Hand
Posts: 31
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Kathy's book says that it is the reference type of the arguments that determines which version of the overloaded method is executed. It does not mention the reference type of the object on which the method is invoked. When I read this, I took it to mean that the reference types of the arguments (and the arguments alone) would determine which version of the method is executed.
But apparently it is something different. Apparently, the reference type of the object on which the method is invoked is also used to determine which version to execute. In fact, it appears to take precedence over the argument reference types.
Can the object on which the method is called be considered an argument of the method? If so, that would clear things up.
[ July 01, 2003: Message edited by: Lisa French ]
 
Andres Gonzalez
Ranch Hand
Posts: 1561
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Originally posted by Lisa French:
...
Can the object on which the method is called be considered an argument of the method? If so, that would clear things up.
[ July 01, 2003: Message edited by: Lisa French ]


I did not get your question... sorry.. can you show me what you meant with an example?
 
Lisa French
Ranch Hand
Posts: 31
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Originally posted by Andres Gonzalez:

I did not get your question... sorry.. can you show me what you meant with an example?


To hopefully clarify: In the method call c1.m1(c2); can c1 be considered an argument to the method?
 
Andres Gonzalez
Ranch Hand
Posts: 1561
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Originally posted by Lisa French:

To hopefully clarify: In the method call c1.m1(c2); can c1 be considered an argument to the method?


hmm... well.. It makes sense what you're trying to conclude, but.. I (personally) wouldn't generalize it to see it in that way. I always see it this way:


The reference type (not the object type) determines which overloaded method is invoked.
Overriden methods are resolved at runtime based on the object type.


It'd be nice to read someone else's opinion.
 
Greenhorn
Posts: 23
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
I have the same problem understanding this problem as Lisa.
I study from the Osborne McGraw-Hill Java 2 certification guide and it says the same thing as Lisa's book.
That the argument type in the method call (ie. C) determines which overloaded method is called, and not the reference type (ie. A).
 
bennido kool kat
Greenhorn
Posts: 23
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
LOL ! ... Just realised mine is the same book as Lisa's ! ... No wonder it says the same thing ... Sorry ...
 
Andres Gonzalez
Ranch Hand
Posts: 1561
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Originally posted by bennido kool kat:
LOL ! ... Just realised mine is the same book as Lisa's ! ... No wonder it says the same thing ... Sorry ...


 
Andres Gonzalez
Ranch Hand
Posts: 1561
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Lisa, page 333 of KnB book ("two minute drill"):


- Polymorphism applies to overriding, not overloading
- Object type determines which overriden method is used at runtime
- Reference type determines which overloaded method is used at compile time


End of story.
 
Lisa French
Ranch Hand
Posts: 31
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
- Polymorphism applies to overriding, not overloading
- Object type determines which overriden method is used at runtime
- Reference type determines which overloaded method is used at compile time

Yes, I've seen that. But reference type of what?
1. The arguments and arguments alone - which is the way I read this in the text of the book.
2. Or the reference type of the arguments AND of the object on which the method is called - which is the way it is turning out to actually be.
My query lies in that what I've read and what actually happens when I run code seem to conflict.
[ July 02, 2003: Message edited by: Lisa French ]
 
Ranch Hand
Posts: 1392
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Part I. Resolving a method name at compile-time:

1. Determine the class or interface to search.
Since the type of the reference c1 is A, the compiler searches class A.
2. Find all methods (declared or inherited) that are applicable and accessible.
Applicable means
(1) The number of parameters in the method declaration equals the number of arguments in the method invocation,
(2) The type of each actual argument can be converted to the type of the parameter.
The method m1(A a) is applicable because the type of the argument C can be converted to the type of the parameter A.
3. Choose the most specific method.
We found only one method in A, so of course it is the most specific. If we had found more than one overloaded method, then we would have to compare parameter types and types where the methods are declared.
4. Make sure the method is appropriate.
(A bunch of rules that do not apply to this example.)
5. Choose the method invocation mode.
(A bunch of rules that do not apply to this example.)
[ July 02, 2003: Message edited by: Marlene Miller ]
 
Marlene Miller
Ranch Hand
Posts: 1392
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Part II. Evaluating a method invocation at run-time:
1. Compute the target reference.
The target reference is an object of class C.
2. Evaluate the arguments.
3. Locate the method to invoke.
Starting with the class C of the target reference, look for a method that overrides the method chosen at compile-time. If not found, look in the superclass.
Since no method in C overrides A.m1(A a), look in B, then A. The method in A is the method to invoke.
[ July 02, 2003: Message edited by: Marlene Miller ]
 
Marlene Miller
Ranch Hand
Posts: 1392
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Part III. Now condensing all of that,
The compiler looks for all applicable and accessible methods (declared or inherited) in the class or interface of the reference type.
Then the compiler chooses the most specific method using the types of the parameters and types of the classes where the methods are declared.
At run-time, the virtual machine looks for a method having the same form (same name, same number of parameters, same parameter types, same return type) as the method chosen at compile time.
The virtual machine starts looking in the class of the actual object. Then it looks in the superclasses.
If some method overrides the method chosen at compile-time, that is the method to invoke. If not, the method chosen at compile-time is the method to invoke.
(See JLS 15.12)
[ July 02, 2003: Message edited by: Marlene Miller ]
 
bennido kool kat
Greenhorn
Posts: 23
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Hmmm ... finally, I THINK I get it ... let a noob like myself give it a go.
c1.m1(c2)
... because c1 is of class type A, the JVM will look in class A for methods called m1. Because there is only 1 method m1, this is used.
However, if the statement was instead ...
c2.m1(c2)
... where c2 is of class C. This time, the JVM will look in class C and will find 3 methods called m1, namely ...
void m1 (A a)
void m1 (B b)
void m1 (C c)
.. Because there are 3 methods called m1, the JVM THEN uses the ARGUMENT TYPE to determine which (overloaded) method to call. In this case, the argument type is class C so void m1 (C c) is called !
And this is what I think Kathy's book is trying to tell us ! The text that Lisa read is only on the latter concept, where in fact this code is the amalgamation of 2 concepts in the book.
Am I right or am I correct ?? ..
 
Andres Gonzalez
Ranch Hand
Posts: 1561
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Originally posted by bennido kool kat:
Hmmm ... finally, I THINK I get it ... let a noob like myself give it a go.
c1.m1(c2)
... because c1 is of class type A, the JVM will look in class A for methods called m1. Because there is only 1 method m1, this is used.
However, if the statement was instead ...
c2.m1(c2)
... where c2 is of class C. This time, the JVM will look in class C and will find 3 methods called m1, namely ...
void m1 (A a)
void m1 (B b)
void m1 (C c)
.. Because there are 3 methods called m1, the JVM THEN uses the ARGUMENT TYPE to determine which (overloaded) method to call. In this case, the argument type is class C so void m1 (C c) is called !
And this is what I think Kathy's book is trying to tell us ! The text that Lisa read is only on the latter concept, where in fact this code is the amalgamation of 2 concepts in the book.


Amen !
 
Marlene Miller
Ranch Hand
Posts: 1392
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Bennido, may I adjust just a few small things with what you said.


the JVM will look in class A for methods called m1


The *compiler* will look in class A for methods called m1.
The *compiler* chooses which class to search. The *compiler* chooses which overloaded form of the method should be invoked, but not which implementation of that method.


Because there is only 1 method m1, this is used.


Yes, there is only 1 method in class A. No choice.
This is the *form* (number of parameters, parameter types, return type) of the method used. It might not be the *implementation* of the method used.
At run time the JVM uses the actual type of the object the method is invoked upon (class C) to find an implementation of the method that was determined at compile time. There is no overriding in this example. So this method is used.


where c2 is of class C. This time, the JVM will look in class C and will find 3 methods called m1


Yes, there are three methods to choose from, one declared and two inherited.
The *compiler* will look in class C and find 3 methods called m1.


Because there are 3 methods called m1, the JVM THEN uses the ARGUMENT TYPE to determine which (overloaded) method to call.


The *compiler* uses the argument type to determine which (overloaded) method to call.
The compiler compares the argument types of the method invocation with the parameter types of the method declarations.
At run time the JVM uses the actual type of the object the method is invoked upon (class C) to find an *implementation* of the method that was determined at compile time.
 
Marlene Miller
Ranch Hand
Posts: 1392
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
One subtle change. I added an overriding method to class C.

C.m1(A)
The *compiler* looks in class A and finds only one method m1(A a).
The *compiler* compares the method invocation and the method declaration. m1(c2) has argument type C. m1(A a) has parameter type A. C can be converted to A. OK.
The JVM must use a method of the *form* m1(A a) because that is what the compiler chose.
The JVM knows the actual type of the object c1 is class C. The JVM looks in class C and finds an *overriding* method m1(A a). The JVM uses the method m1(A a) in class C.
[ July 02, 2003: Message edited by: Marlene Miller ]
 
Ranch Hand
Posts: 443
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
The way I see it, perhaps this is oversimplication, is that when you compile a program like this, the compiler has no choice but to use the reference to locate the most specific method. It cannot use the object pointed to by the reference because it does not know where it will be pointing at later on. Only at runtime will it know what is the actual object. Then only at that time it can say that this method has been overridden in this object and therefore it must use the new method.
Just my $0.02.
 
With a little knowledge, a cast iron skillet is non-stick and lasts a lifetime.
reply
    Bookmark Topic Watch Topic
  • New Topic