• 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

Covariant problem

 
Ranch Hand
Posts: 69
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
What is the result of compiling and runing the following program?

class A {
int x = 5;
}

class B extends A { int x = 6 }

public class CovariantTest {
public A getObject() { return new A(); }
public static void main(String[] args) {
CovariantTest c1 = new SubCovariabntTest();
System.out.println(c1.getObject.x);
}
}

class SubCovariantTest extends CovariantTest {
public B getObject() {
return new B();
}
}

[A] Does not compile [B] Throw ClassCastException [C] prints 5 [D] prints 6

My answer is D. But the answer is actually C. Can some one give idea why?

As Covariant class it should use SubCovariantTest's getObject, if so then it should return Type B not A, then it should print 6 not 5 here?
 
Ranch Hand
Posts: 179
Mac Eclipse IDE Chrome
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
hi Henry Zhi Lin ,
welcome to javaranch.

Can you mention the source for the program. As mentioned in this
 
Greenhorn
Posts: 9
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Hi Henry,

Actually, you have a compiler error in your code. You are overriding method getObject(), however you are using two different return type Objects. You have public A getObject(){} and public B getObject(){}. This is an illegal override. If you were to legally override the method, then the method called would be the method of the reference type object, CovarientTest.getObject().

Hope this helps,

Jennifer
 
Ranch Hand
Posts: 30
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
This is actually legal code -

Prior to Java 5, we were not able to change the return type for any return type of an overriding method. As of Java 5, an overriding method may return a subclass of the return type of the overridden method. This works because the retuned object is "reduced" to the type of its supertype - in this case, type A. So SubCovariantTest's getObject is running. In this example, the c1.getObject() is returning an object of type B, except it is returned in the type of it's supertype - type A.


In effect:
////////////////////////////////
Calling:
A myResultingA = c1.getObject() (this returns type B via a reference of type A)

is similar to:
List<Integer> myList = new ArrayList<Integer>();
////////////////////////////////////

Try casting the result of c1.getObject() - it should print 6. It also helped me to put a print statement in each method.

class A {
int x = 5;
}

class B extends A { int x = 6 }

public class CovariantTest {
public A getObject() { return new A(); }
public static void main(String[] args) {
CovariantTest c1 = new SubCovariabntTest();
System.out.println(((B)c1.getObject()).x);
}
}

class SubCovariantTest extends CovariantTest {
public B getObject() {
System.out.println("SubCovariantTest is running");
return new B();
}
}

In most of the exam questions I've run across, this isn't an issue, as we're just testing to see which method ran - and not what the effect of the return type really is.

Good luck! I have my test tomorrow - yikes.
[ November 04, 2008: Message edited by: Steven Landers ]
 
Sheriff
Posts: 9707
43
Android Google Web Toolkit Hibernate IntelliJ IDE Spring Java
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Steven gave a good explanation here. The original code works in this manner


[ November 04, 2008: Message edited by: Ankit Garg ]
 
Greenhorn
Posts: 28
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
If I may chime in (and put my head on the chopping block at the same time ), it appears to me that the new covariant feature of Java 5 is allowing the sub-type to be different, however, this doesn't appear (to me anyways) to be a covariant/contravariant/invariant issue pertaining to the OP's question. This is more of polymorphic behavioral issue - specifically what is considered a compile-time decision and what is considered a run-time decision. The above code reworded, and with an addition:




Two things above that are of interest:
1) Whether using the new invariant behavior or not, the output is the same. That is, with or without the invariant feature invoked, the output doesn't change.
2) Within the context of polymorphic behavior, an instance variable is decided at compile time whereas the instance method is decided at runtime (i.e., 5 is printed from the A class, but "Ima 'B'" is printed from the B class.

I don't know if the test gets this ugly, but this is something nice to know - at least if you're dealing with large/complex class hierarchies.

On a side note, if you are looking for an interesting read on invariants, this is a good read:
http://barrkel.blogspot.com/2006/07/covariance-and-contravariance-in-net.html

I found the descriptions quite informative.
 
Java Cowboy
Posts: 16084
88
Android Scala IntelliJ IDE Spring Java
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Henry, welcome to JavaRanch.

We have a rule here: when you copy a question from a book, mock exam or other source, you are required to quote your sources. So, please tell us where you copied this question from.
 
Henry Zhi Lin
Ranch Hand
Posts: 69
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Originally posted by Ravikanth kolli:
hi Henry Zhi Lin ,
welcome to javaranch.

Can you mention the source for the program. As mentioned in this



This question from WhizLabs. I do appologies, there are lots of miss typing.

The following should be a compiled code.

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

Originally posted by Steven Landers:
This is actually legal code -

Prior to Java 5, we were not able to change the return type for any return type of an overriding method. As of Java 5, an overriding method may return a subclass of the return type of the overridden method. This works because the retuned object is "reduced" to the type of its supertype - in this case, type A. So SubCovariantTest's getObject is running. In this example, the c1.getObject() is returning an object of type B, except it is returned in the type of it's supertype - type A.


In effect:
////////////////////////////////
Calling:
A myResultingA = c1.getObject() (this returns type B via a reference of type A)

is similar to:
List<Integer> myList = new ArrayList<Integer>();
////////////////////////////////////

Try casting the result of c1.getObject() - it should print 6. It also helped me to put a print statement in each method.

class A {
int x = 5;
}

class B extends A { int x = 6 }

public class CovariantTest {
public A getObject() { return new A(); }
public static void main(String[] args) {
CovariantTest c1 = new SubCovariabntTest();
System.out.println(((B)c1.getObject()).x);
}
}

class SubCovariantTest extends CovariantTest {
public B getObject() {
System.out.println("SubCovariantTest is running");
return new B();
}
}

In most of the exam questions I've run across, this isn't an issue, as we're just testing to see which method ran - and not what the effect of the return type really is.

Good luck! I have my test tomorrow - yikes.

[ November 04, 2008: Message edited by: Steven Landers ]




Thanks for your answer, now I do understand it a bit of clear.
 
Henry Zhi Lin
Ranch Hand
Posts: 69
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Hi guys,

Thanks for all your answers. Now I do have a clue why this convariant class behaves like this.

Thanks for all your help.
 
Ranch Hand
Posts: 101
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Can anybody explaim why there is refence type is selected incovariant overrinding.
 
Henry Zhi Lin
Ranch Hand
Posts: 69
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
I guess this is downto the following statement

Object type (not the reference variable's type), determines which overridden
method is used at runtime.

Reference variable type (not the Object type), determines which instance variable is used at compile time.
 
Ranch Hand
Posts: 220
Eclipse IDE Spring Java
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
YES
 
Ranch Hand
Posts: 178
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Its understood that the object type determines which overridden method should be invoked at runtime.

then, why does the following code runs the way it runs? (From one of the replies above from Ankit in this mail thread)



I am specifically not clear on this...Why does not B b = c1.getObject(); compile without a (B) cast?

I thought for this function call, SubCovariantTest's getObject() would be called and the resulting B object could be assigned to b reference variable...But seems that is not the case... Anyone please clarify this doubt of mine.
 
Ranch Hand
Posts: 362
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
i am confused.....

can anyone give clarification?
 
Arron Ferguson
Greenhorn
Posts: 28
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

I guess this is downto the following statement

Object type (not the reference variable's type), determines which overridden
method is used at runtime.

Reference variable type (not the Object type), determines which instance variable is used at compile time.



Yes, correct. Which really has nothing to do with covariance - at least not with the code example you posted since you can duplicate the same behavior without using the covariant feature of Java 5.
 
Rekha Srinath
Ranch Hand
Posts: 178
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Arron,

Yes, you are right. Those statements in your quotes can be explained without bringing in covariance.

But, I am unable to understand why B b = c1.getObject(); does not compile without a (B) cast
 
Jennifer Gamble
Greenhorn
Posts: 9
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
My apologies. I compiled the code above on the older java 1.4 compiler. I had forgotten that overriding methods are allowed to return subtype objects as of java 5.
 
Arron Ferguson
Greenhorn
Posts: 28
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Arron,

Yes, you are right. Those statements in your quotes can be explained without bringing in covariance.

But, I am unable to understand why B b = c1.getObject(); does not compile without a (B) cast



Because it's a downcast. The c1 variable is of type CovariantTest. CovariantTest's getObject method returns an 'A' type object. You're telling it to put (force really) an 'A' instance into a 'B' reference. You are thus going down the inheritance hierarchy and therefore you are performing a downcast.

The Java compiler wants you to be good and sure you are aware of this because it could cause problems. For example, you could start off with a Cat object (whose superclass is Animal), and then use an animal reference to the Cat object (upcast). Then you later (and erroneously) take the animal reference and downcast it to a Dog (whose superclass is also Animal). As we know, you can never turn a dog into a cat (or vice versa - very unnatural!). The Java VM would throw a ClassCastException (possibly) causing problems in your program state.

A good read is found here:
http://javaforyou.wordpress.com/2008/06/22/casting-reference-variables-downcasting-upcasting/
 
Ganeshkumar cheekati
Ranch Hand
Posts: 362
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Hi arron.

c1.getObject();
it will call the getObject method in the sub class because of overriding and it returns B object.
 
Arron Ferguson
Greenhorn
Posts: 28
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Hi arron.

c1.getObject();
it will call the getObject method in the sub class because of overriding and it returns B object.



Uh no, no it does not, it returns 5. Run the code, read the blog link article and see for yourself, the downcast rules are clear.
 
subhasish nag
Ranch Hand
Posts: 101
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Uh no, no it does not, it returns 5.


Yes.that is the problem why c1.getObject() is not returning B instead of A.
Here as it overriding so object type(CovariantTest c1 = new SubCovariabntTest() to be choosed as runtime ,as a result
public B getObject(){} to be invoked (which return B not A).Can anybody please explain this.
But when I change the code
CovariantTest c1 = new SubCovariantTest();
B b = (B)(c1.getObject());
System.out.println(b.x);
It will return 6.
So the question is actually
Is the covariant overriding has some more special characteristics??
 
Ganeshkumar cheekati
Ranch Hand
Posts: 362
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
hi arron..
i read it.
i think that is the situation in which method is only available in sub class but not in super class.
we can't call that method using super class ref so we have to do downcasting...

by executing below code we know which method is executing (super or sub)

class A {
int x = 5;
}

class B extends A
{
int x = 6; }

public class CovariantTest {
public A getObject() {
System.out.println("super method:");return new A(); }
public static void main(String[] args) {
CovariantTest c1 = new SubCovariantTest();
System.out.println(c1.getObject().x);
}
}

class SubCovariantTest extends CovariantTest {
public B getObject() {
System.out.println("sub method:");
return new B();
}
}
[ November 05, 2008: Message edited by: Ganeshkumar cheekati ]
 
Ankit Garg
Sheriff
Posts: 9707
43
Android Google Web Toolkit Hibernate IntelliJ IDE Spring Java
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
what the heck is happening here??? Everyone should go and read a book instead of being confused like this...
 
Ganeshkumar cheekati
Ranch Hand
Posts: 362
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
thats good thing ankit.

what is your explanation regarding this topic?
 
Rekha Srinath
Ranch Hand
Posts: 178
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Arron,

Thanks for the explanation.I think I got it...

c1.getObject(); -- This line of code, at runtime, can invoke either the
Case 1: getObject() of CovariantTest or
Case 2: SubCovariantTest,
depending on the type of object that c1 points to. This is a purely a runtime decision and we cannot control it during compilation.

Case 1: If the getObject() of CovariantTest is invoked, then an object A is returned. So, you do the downcast using the code (B)c1.getObject(), thus safely assigning a B type object to a B type reference.

Case 2: If the getObject() of SubCovariantTest is invoked, then an object B is returned, which can again be safely assigned to the B type reference. (The cast (B) is meaningless in this case).

So, to provide this safety measure, the compiler ensures that you downcast to avoid ClassCastException, because at runtime, the reference invoking getObject() can be either CovariantTest or SubCovariantTest.

In case of overriding not involving any covariant return types, there is no issue at all, because the return types of the parent and subclass methods are going to be the same.

Correct me if I am wrong in my understanding.
 
reply
    Bookmark Topic Watch Topic
  • New Topic