Win a copy of Beginning Java 17 Fundamentals: Object-Oriented Programming in Java 17 this week in the Java in General forum!
  • 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:
  • Tim Cooke
  • Campbell Ritchie
  • Ron McLeod
  • Liutauras Vilda
  • Jeanne Boyarsky
Sheriffs:
  • Junilu Lacar
  • Rob Spoor
  • Paul Clapham
Saloon Keepers:
  • Tim Holloway
  • Tim Moores
  • Jesse Silverman
  • Stephan van Hulst
  • Carey Brown
Bartenders:
  • Al Hobbs
  • Piet Souris
  • Frits Walraven

Covariant returns

 
Ranch Hand
Posts: 58
2
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator


This code prints 5, because x1.getObject returns a new A.

My stupid brain tells me it should return a new B, because Y overrides X's getObject method (using a covariant return). Please explain.

Thanks,

Gordy
 
Ranch Hand
Posts: 893
Tomcat Server Java Ubuntu
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
You're right that Y extends X and that you're overriding method getObject() in Y from X. This method is also called.

By overriding the JVM also calls the method getObject within Y which is the runtime type. This method returns Object B which is a referance to Object A.
This method returns 5 from Object A, because polymorphic method invocations apply only to instance methods and not to static methods and variables.

I hope is explanation helps.
 
Greenhorn
Posts: 22
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
This is one of those tricky things, which is a perfect case of where encapsulation should be used. If you put this code into an IDE, i.e. Eclipse, and throw it in debug mode you will actually see that there are two variables created here... a(a) and a(b). This is because you do not override variables in a subtype, you actually hide them... it's a slightly different concept.

Therefore, you are correct that you get back an object of B(), however your reference variable is of type A. So the program thinks you want the variable from an A object, and gives you the a(a) version. Now, if you actually use getters and setters, you will see that the application will perform more as expected, try this code where I just added comments, and used a getter method instead of trying to directly call the variable:

 
Gordon Brown
Ranch Hand
Posts: 58
2
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Remko,

Many thanks for your reply.

I get the polymorphic invocation issue the instance variable issue.

The thing I'm struggling with is, given that it's a B object that's returned by the method that's actually called at runtime (i.e. Y's getObject()), why is this an A?

 
Gordon Brown
Ranch Hand
Posts: 58
2
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Thanks, Dustin!
 
Ranch Hand
Posts: 2412
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Originally posted by Gordy Bone:
Remko,

Many thanks for your reply.

I get the polymorphic invocation issue the instance variable issue.

The thing I'm struggling with is, given that it's a B object that's returned by the method that's actually called at runtime (i.e. Y's getObject()), why is this an A?



If you take a look at the methods created in the bytecode, you can see a little better what is happening.



Notice that in the Y class, there are two methods listed with name getObject, one with return type B, and one with return type A.

In previous versions of Java, an overridding method had to have the same return type as the overridden method.

But now with covariant returns, you can modify the return type.

So what's happened is that an extra method has been inserted into Y that has return type A. This method is called a bridge method and simply invokes the overridden method in B.

The bridge method only becomes important when the type of reference used to invoke the overridden method is a superclass reference.

Since the reference type is X, and X defines a method called getObject with return type A, the bridge method in Y, which also has return type A, is used to call the overridden method.

So the overridden method is still called, but its called through a method with return type A, so that is why the object returned from getObject has reference type A.
 
Gordon Brown
Ranch Hand
Posts: 58
2
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Thank you for that explanation, Keith. I was just about to post another query, but I get it now.

Cheers!

Gordy
 
Greenhorn
Posts: 6
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Dear Keith,
I am still not very clear with your explaination.
DO you mean to say that an overridden method is called with the prototype of an inherited one?
These things are not explained in K&B's book..By going by the book I would definitely go with the answer to be the instance variable(a) of class B and not of class A

Oops..I am in a fix..
 
Keith Lynn
Ranch Hand
Posts: 2412
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
In some cases, an overridden method has the same return type as the overriding case. So it is clear what method to call.

In all cases, the reference type decides which methods are allowed to be called.

In this example, the reference type is of type X. X only has a method named getObject() with return type A. However, since the overriding class modifies the return type, there is no version of getObject() with return type A in Y. So the compiler adds one that simply acts as a bridge.

When a reference of type X is used to call getObject() on an instance of type Y, then the method with return type A in Y is called. But this method just calls the overridden method getObject().

The variable returned is of runtime type B.

But the reference type is type A.
 
WHAT is your favorite color? Blue, no yellow, ahhhhhhh! Tiny ad:
Building a Better World in your Backyard by Paul Wheaton and Shawn Klassen-Koop
https://coderanch.com/wiki/718759/books/Building-World-Backyard-Paul-Wheaton
reply
    Bookmark Topic Watch Topic
  • New Topic