Win a copy of The Little Book of Impediments (e-book only) this week in the Agile and Other Processes forum!
  • Post Reply
  • Bookmark Topic Watch Topic
  • New Topic

Not sure why my answer on overloading was incorrect

 
Warren Weis
Greenhorn
Posts: 14
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
I chose this for the true statement on a sample question:

"The reference type determines which implementation is executed for overloaded methods."

The statement that was said to be true was

"The object type determines which implementation is executed for overridden methods."

It seems to me that both are true.

Here is a toy program that executes the overloaded method of the reference type, not the object it is pointing to. What am I missing here? I did not understand their explanation.



the output is

Number
A
 
Maneesh Godbole
Saloon Keeper
Posts: 11341
16
Android Eclipse IDE Google Web Toolkit Java Mac Ubuntu
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Hint: So what do you think you will get if you use
 
Warren Weis
Greenhorn
Posts: 14
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Hi Maneesh:

In answer to your question, I get what I would expect: the method taking a 'B' class instance parameter is called. Meanwhile, I have found this thread on JavaRanch:

http://www.coderanch.com/t/488162/java-programmer-SCJP/certification/Overloading-Overriding-Reference-object-type

and this quote from the Kathy Sierra and Bert Bates SCJP 6.0 Book on page 113:

"Just remember, the reference type (not the object type) determines which overloaded method is invoked!"

I am thinking more and more that the answer to this test question is just wrong. Which would be a shame, as it is from Kaplan Testing, which I purchased through Oracle and was rather expensive.
 
Roel De Nijs
Sheriff
Posts: 10662
144
AngularJS Chrome Eclipse IDE Hibernate Java jQuery MySQL Database Spring Tomcat Server
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
It's very important to know for the exam, because many questions have overloaded/overridden methods and you need to know if code is valid or not before you can start working out the (complex) logic.

I always use these 2 rules:
  • the reference type determines which methods you can invoke
  • which method is actually executed is based on the object type
  •  
    Guillermo Ishi
    Ranch Hand
    Posts: 789
    C++ Linux Python
    • Mark post as helpful
    • send pies
    • Quote
    • Report post to moderator




    If Integer had a method m1(x) it would be called instead of an overridden method belonging to Number. What you think is happening isn't happening. It's a bit subtle. a = new B() will call B's method if it overrides a method in A. With overloading, a = new B() will end in a call to whichever (from A or B) matches the parameter list you use in your call. The complexity increases when overrides throw different exceptions or the visibility modifier changes.
     
    Roel De Nijs
    Sheriff
    Posts: 10662
    144
    AngularJS Chrome Eclipse IDE Hibernate Java jQuery MySQL Database Spring Tomcat Server
    • Mark post as helpful
    • send pies
    • Quote
    • Report post to moderator
    Guillermo Ishi wrote:



    If Integer had a method m1(x) it would be called instead of an overridden method belonging to Number. What you think is happening isn't happening. It's a bit subtle. a = new B() will call B's method if it overrides a method in A. With overloading, a = new B() will end in a call to whichever (from A or B) matches the parameter list you use in your call. The complexity increases when overrides throw different exceptions or the visibility modifier changes.

    That's not completely true!
  • For starters, in this example Integer doesn't have a m1 method, it's the Test class which defines this method.
  • Secondly, the statement "a = new B() will end in a call to whichever (from A or B) matches the parameter list you use in your call" is not true. If reference variable a is of type A, you can ONLY invoke methods from class A. You can't invoke methods which are only defined in class B using a reference variable of type A (doesn't matter what the type of the actual object is).
  • Finally, for a valid method override you have to meet some must rules regarding method name, argument/parameter list, return type, access modifier and exceptions. For a valid method overload you have less must rules (only method name and argument/parameter list) to fulfill.
  •  
    Guillermo Ishi
    Ranch Hand
    Posts: 789
    C++ Linux Python
    • Mark post as helpful
    • send pies
    • Quote
    • Report post to moderator
  • Yes. But I think he was expecting the result you would get if Integer itself had the m1 method.
  • By golly, you're right It's a compile error if the base class didn't have a matching method but I was thinking you could call either one. But if they both had a matching method it would be an override. Didn't think it all the way through this time
  • Yes.
  •  
    Warren Weis
    Greenhorn
    Posts: 14
    • Mark post as helpful
    • send pies
    • Quote
    • Report post to moderator
    Many of the replies I have received seem to think I was asking a question about polymorphism (overriding). I was not. I was asking about what determines which method is picked for overloading.

    To clarify: is this sentence from the Kathy Sierra and Bert Bates SCJP 6.0 Book on page 113 correct?

    "Just remember, the reference type (not the object type) determines which overloaded method is invoked!"

    If it is not, why?

    Thanks.

    Here is the full paragraph, so that the sentence can be seen in context:

    "Even though the actual object at runtime is a Horse and not an Animal, the
    choice of which overloaded method to call (in other words, the signature of the
    method) is NOT dynamically decided at runtime. Just remember, the reference
    type (not the object type) determines which overloaded method is invoked! 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. If you invoke a method passing it an Animal
    reference to a Horse object, the compiler knows only about the Animal, so it
    chooses the overloaded version of the method that takes an Animal. It does not
    matter that at runtime there's actually a Horse being passed."
     
    Paul Anilprem
    Enthuware Software Support
    Ranch Hand
    Posts: 3819
    10
    • Mark post as helpful
    • send pies
    • Quote
    • Report post to moderator
    Warren Weis wrote:
    "Just remember, the reference type (not the object type) determines which overloaded method is invoked!"


    This statement is correct but if taken out of context, it could cause confusion because the term "invocation" could imply the runtime execution of the method as well, while this statement is talking about compile time.
    If it helps, you may rewrite it as, ""Just remember, the reference type (not the object type) determines which overloaded method is picked by the compiler".

    At run time, of course, the JVM will see if the actual object referred to by the reference overrides the method and if so, it will invoke the method on that object.


    Added later: I would not even bring the discussion of Horse/Animal while discussing overloading because that is a concept that plays out entirely at run time. It has nothing to do with overloading at all. Simply put, no matter what method you call in code, the compiler will always look at the reference type and see if the call is valid. Indeed, the compiler has no knowledge of the actual object so all it can do is check the reference type and pick the method signature that is to be invoked at run time. The JVM takes a look at the method signature (which was picked by the compiler), checks which object is the target of the call and invokes the method on that object.

    HTH,
    Paul.
     
    Warren Weis
    Greenhorn
    Posts: 14
    • Mark post as helpful
    • send pies
    • Quote
    • Report post to moderator
    Thank you for your reply, Paul. My problem, then, on the practice test I was taking, was that I took this statement (from the test):
    "The reference type determines which implementation is executed for overloaded methods."

    to be the equivalent of this statement, from the Bates/Sierra book:
    "Just remember, the reference type (not the object type) determines which overloaded method is invoked!"

    The first statement was considered incorrect by the authors of the problem this was part of.
    I can only hope that I do not run into questions of this nature on the real test!
     
    Guillermo Ishi
    Ranch Hand
    Posts: 789
    C++ Linux Python
    • Mark post as helpful
    • send pies
    • Quote
    • Report post to moderator
    "The reference type determines which implementation is executed for overloaded methods."

    You want that to be a false answer in the practice test. If you cast a to a B in the call to m1 it will call the overloaded method that takes a B. In that case you're telling the overloaded method about the object type, and the reference has nothing to do with which is called.


     
    Roel De Nijs
    Sheriff
    Posts: 10662
    144
    AngularJS Chrome Eclipse IDE Hibernate Java jQuery MySQL Database Spring Tomcat Server
    • Mark post as helpful
    • send pies
    • Quote
    • Report post to moderator
    Warren Weis wrote:Thank you for your reply, Paul. My problem, then, on the practice test I was taking, was that I took this statement (from the test):
    "The reference type determines which implementation is executed for overloaded methods."

    to be the equivalent of this statement, from the Bates/Sierra book:
    "Just remember, the reference type (not the object type) determines which overloaded method is invoked!"

    It's a very subtle difference, but I'm inclined to say the test was/is correct and that statement is false. Although the word "implementation" can be considered very ambiguous. In your original post you said "I did not understand their explanation.". Can you share their explanation?


    Warren Weis wrote:I can only hope that I do not run into questions of this nature on the real test!

    No need to worry! The actual exam is very well written and you don't have to face such dubious/unclear questions.
     
    Roel De Nijs
    Sheriff
    Posts: 10662
    144
    AngularJS Chrome Eclipse IDE Hibernate Java jQuery MySQL Database Spring Tomcat Server
    • Mark post as helpful
    • send pies
    • Quote
    • Report post to moderator
    Guillermo Ishi wrote: "The reference type determines which implementation is executed for overloaded methods."

    If you cast a to a B in the call to m1 it will call the overloaded method that takes a B. In that case you're telling the overloaded method about the object type, and the reference has nothing to do with which is called.

    That's obviously cheating If you cast (without reassigning to another reference variable), you (temporarily) change the reference type just for that 1 moment/usage.

    For example:

    The statement ((CharSequence)o).length() could be rewritten as CharSequence tmp = (CharSequence)o; tmp.length();. So you temporarily changed the reference type (otherwise you could never invoked the length() method). And line 3 proves you can only invoke the methods from the type you use when casting (CharSequence) and not from the actual object (String).

    A similar example with overloaded methods:

    Although the object type is String, only when you temporarily change the reference type to String using a cast (in line 3) the overloaded method using a String parameter is invoked.
     
    Guillermo Ishi
    Ranch Hand
    Posts: 789
    C++ Linux Python
    • Mark post as helpful
    • send pies
    • Quote
    • Report post to moderator
    I'm not above some good honest cheating


    We demonstrated the same thing. The question now is does the cast affect the reference really, or does the cast cause a different object to be passed. If it's the latter then we showed that which method gets called can depend on the object, instead of the reference. Showing that "The reference type determines which implementation is executed for overloaded methods" really is wrong as claimed.
     
    Paul Anilprem
    Enthuware Software Support
    Ranch Hand
    Posts: 3819
    10
    • Mark post as helpful
    • send pies
    • Quote
    • Report post to moderator
    Guillermo Ishi wrote:
    We demonstrated the same thing. The question now is does the cast affect the reference really, or does the cast cause a different object to be passed. If it's the latter then we showed that which method gets called can depend on the object, instead of the reference. Showing that "The reference type determines which implementation is executed for overloaded methods" really is wrong as claimed.

    It's not the same thing. An object, once created, can never change. It is the reference that changes (temporarily). http://docs.oracle.com/javase/specs/jls/se7/html/jls-5.html#jls-5.5.1
     
    Guillermo Ishi
    Ranch Hand
    Posts: 789
    C++ Linux Python
    • Mark post as helpful
    • send pies
    • Quote
    • Report post to moderator
    Paul Anilprem wrote:
    It's not the same thing. An object, once created, can never change. It is the reference that changes (temporarily). http://docs.oracle.com/javase/specs/jls/se7/html/jls-5.html#jls-5.5.1


    We both demonstrated changing which overloaded method was called by applying a cast to the reference passed to the method, the way I saw it.

    But the bottom line is are you saying when the cast is applied it does not cause a different object (an object of a different type) to be passed to the method? If the reference is a pointer and the cast doesn't change its value, then what does the cast do?


     
    Paul Anilprem
    Enthuware Software Support
    Ranch Hand
    Posts: 3819
    10
    • Mark post as helpful
    • send pies
    • Quote
    • Report post to moderator
    Guillermo Ishi wrote:
    But the bottom line is are you saying when the cast is applied it does not cause a different object (an object of a different type) to be passed to the method?

    Yes, that is exactly what I am saying. An object cannot change. Think about it. If you have a dog, can it change to something else?

    If the reference is a pointer and the cast doesn't change its value, then what does the cast do?

    The cast just tells the compiler to treat the referenced object as something else. You can treat a Dog like an Animal (or "try" to treat an Animal like a Dog). But that doesn't really change the dog. The dog remains a Dog
     
    Roel De Nijs
    Sheriff
    Posts: 10662
    144
    AngularJS Chrome Eclipse IDE Hibernate Java jQuery MySQL Database Spring Tomcat Server
    • Mark post as helpful
    • send pies
    • Quote
    • Report post to moderator
    Guillermo Ishi wrote:We demonstrated the same thing. The question now is does the cast affect the reference really, or does the cast cause a different object to be passed. If it's the latter then we showed that which method gets called can depend on the object, instead of the reference. Showing that "The reference type determines which implementation is executed for overloaded methods" really is wrong as claimed.


    Guillermo Ishi wrote:But the bottom line is are you saying when the cast is applied it does not cause a different object (an object of a different type) to be passed to the method? If the reference is a pointer and the cast doesn't change its value, then what does the cast do?


    It seems my previous post didn't have the result I was aiming for. Let's try to explain it again with a (fictional) real world example and you play the leading role

    Besides being a human Guillermo is also a son (to his parents), a brother (to his siblings), a boyfriend (to his girlfriend) and a runner (preparing for a 10 miles run). In the Java world this looks like this:



    So the object itself never changed. But the object can be approached in several different ways, each which its own behavior. And that's exactly what casting does too: you are able to use specific behavior of an object, but the type of the object itself doesn't change.

    Hope it helps!
     
    Guillermo Ishi
    Ranch Hand
    Posts: 789
    C++ Linux Python
    • Mark post as helpful
    • send pies
    • Quote
    • Report post to moderator
    You know too much about me. I need to clear my cookies

    Thanks for the effort your example took.

    I think I see what is going on - when you instantiate a subclass you create a class that actually contains its superclasses. Are independent instances of the superclasses also created - does B() create both a B and an instance of its superclass A? I had been thinking the cast caused the reference to refer to a different independent object created by the chain of constructors. If that was the case (B)a == a should evaluate to false but it doesn't.
     
    Roel De Nijs
    Sheriff
    Posts: 10662
    144
    AngularJS Chrome Eclipse IDE Hibernate Java jQuery MySQL Database Spring Tomcat Server
    • Mark post as helpful
    • send pies
    • Quote
    • Report post to moderator
    Guillermo Ishi wrote:Are independent instances of the superclasses also created - does B() create both a B and an instance of its superclass A?

    NO!

    Consider this:


    Now when I create an instance of Lion (using Lion's constructor) Lion lion = new Lion(); all its superclasses' constructors will run, so that means all these constructors will run (in this order):
  • Object (the implicit parent of Animal)
  • Animal
  • Carnivore
  • Lion


  • In the end you'll have 1 object (a Lion instance) which is referred by the reference variable lion. And 4 constructors were executed to correctly create this 1 object (but you do NOT have 4 different instances of all its superclasses). You only have 1 instance!
     
    Guillermo Ishi
    Ranch Hand
    Posts: 789
    C++ Linux Python
    • Likes 1
    • Mark post as helpful
    • send pies
    • Quote
    • Report post to moderator
    Roel De Nijs wrote: And 4 constructors were executed to correctly create this 1 object (but you do NOT have 4 different instances of all its superclasses). You only have 1 instance!


    Ok, that was the core of my misunderstanding. I didn't think Paul's dog was changing but I thought the cast swapped the dog. Thanks again.
     
    • Post Reply
    • Bookmark Topic Watch Topic
    • New Topic