• 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

Rules of method overloading broken??

 
Ranch Hand
Posts: 37
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
NOTE: This discussion and all examples within assume the use of Java 5.0

The Code... what appears to be a override of speak() in Second.



Second is not being overridden, its being overloaded ( or some strange thing like overloading ). But wait you say, the rule for overloads is that the argument list ( the signiture of the method ) must be different, so the compiler knows which one to call. That is what I thought too...

Covariant return types in Java 5. The rule states that "a method in a subclass may return an object whose type is a subclass of the type returned by the method with the same signature in the superclass."

Now lets break down this example as I see it. I see a super class named First, and a sub class named Second. The subclass overrides the speak() method, and because of Java 5's covariant return type rule, changes to return type to String. String is a subclass of Object, so this is legal in Java 5. Now we have a main method, create a reference of type First named obj that points to a instance of Second. Ah now some standard subtype polymorphism about to happen ... the compiler will use dynamic method lookup to see that obj points to a Second and will call the overridden version of speak in Second. OHHH WTF ITS TRYING TO USE THE VERSION IN FIRST??? How could this be I thought to myself.

I went and re-read all about overriding and overloading methods, some polymorphism stuff, rules about covaraint return types.. bla bla bla to make sure I didnt forget some rule. Why oh why was it calling the superclass version, when it should be calling the version in the class that the obj reference points to...

So I then use reflection to find out just what methods the subclass has. I wrote a function that takes in a reference to an object, and then prints out all information about that objects methods. So using it like this


Prints out:

Name: method1
Return Type: java.lang.Object
Parameter Types:
Name: method1
Return Type: java.lang.String
Parameter Types:
Name: hashCode.....then all the other methods in Object like toString etc.

It overloads the method, instead of overriding it. Is that what is going on here? This breaks all the rules of overloading if so.. What is the point of this feature?
 
Wanderer
Posts: 18671
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
[Kenny]: Second is not being overridden, its being overloaded

No, nothing in this problem is being overloaded. The method speak() in First is being overridden bey the method speak() in Second. That's it.

[Kenny]: Ah now some standard subtype polymorphism about to happen ... the compiler will use dynamic method lookup to see that obj points to a Second and will call the overridden version of speak in Second. OHHH WTF ITS TRYING TO USE THE VERSION IN FIRST??? How could this be I thought to myself.

The compiler does not use dynamic method lookup, ever. "Dynamic" means the lookup occurs at run time, after the compiler has, errr, compiled. At compile time, the compiler simply assumes that reference obj holds and instance of the declared type of the reference, which is First. You've told the compiler it's a First, and the compiler will continue to assume it's a First. Sure, you've put a Second instance in there, and that's pretty obvious in this case. But the compiler is still just going to assume it's a First, because that's what it's required to do. And because compile-time determination of what type a reference "really" has is often much more complex than it is here, or even impossible. It's much simpler for everyone if the compiler gives consistent behavior that is easy to predict - and the best way to do that, in the opinion of Java's designers, is for the compiler to just assume that a reference holds it's declared type, period. So obj holds a First, and speak() in First returns a String, period - as far as the compiler is concerned. If you want the compiler to treat obj as a Second, you need to declare it as a Second.
 
Ranch Hand
Posts: 122
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Mhhh.

So obj holds a First, and speak() in First returns a String, period - as far as the compiler is concerned.


speak() in First returns an Object(which is a String), as far as the compiler is concerned. And an Object cannot be implicitly casted to a String in , there must be an explicit cast like

[ January 13, 2007: Message edited by: Anton Uwe ]
[ January 13, 2007: Message edited by: Anton Uwe ]
 
author and iconoclast
Posts: 24207
46
Mac OS X Eclipse IDE Chrome
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
I think the thing you may be missing is that while, as Jim says, the compiler can only use the method signatures that appear in First when compiling method calls on a reference variable of type First, if you change that last line to use an Object variable, compile and run the code, you'll see that the overrridden method in class Second is the one that is actually invoked. Try it.
 
Kenny Johnson
Ranch Hand
Posts: 37
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Oops Im' sorry, I ment to say the JVM will perform dynamic method lookup.Also, if there is no overloading taking place, why does reflection say Second contains both methods?
[ January 13, 2007: Message edited by: Kenny Johnson ]
 
Anton Uwe
Ranch Hand
Posts: 122
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Yes. if you replace the last line with (just inserting the cast to String), the compiler is happy and the JVM will call the speak()-method of class Second.
 
Jim Yingst
Wanderer
Posts: 18671
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
[Jim]: So obj holds a First, and speak() in First returns a String,

I misspoke here; the return type is Object.

[Kenny]: Also, if there is no overloading taking place, why does reflection say Second contains both methods?

This is a side effect of how they've implemented covariant returns, redeclaring the superclass method in the subclass with the old return type, and having that methods forward to the the new method. The redeclared method is called a bridge - it's an implementation detail seen by the JVM, not normally accessible from Java source code (other than through reflection). Note that if you try to invoke the First method using an instance of Second, you will still get the subclass method, not the superclass. That's overriding.

[ January 13, 2007: Message edited by: Jim Yingst ]
 
reply
    Bookmark Topic Watch Topic
  • New Topic