• 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
  • Liutauras Vilda
  • Ron McLeod
  • Jeanne Boyarsky
  • Paul Clapham
Sheriffs:
  • Junilu Lacar
  • Tim Cooke
Saloon Keepers:
  • Carey Brown
  • Stephan van Hulst
  • Tim Holloway
  • Peter Rooke
  • Himai Minh
Bartenders:
  • Piet Souris
  • Mikalai Zaikin

Casting super class to sub class

 
Ranch Hand
Posts: 67
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Look at the following snippet:


Why is 2 running ok??
 
Sheriff
Posts: 11343
Mac Safari Java
  • Likes 1
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Welcome to JavaRanch!

As you know, all objects have a type. The thing to keep in mind is the true runtime type of the object. This is the type of object that was created with "new." Once an object is created, its true runtime type never changes.

But references (stored in variables) also have types. A variable referencing an object can be the same type as that object, or it can be any supertype of that object. For example, a variable that is type "Car" can reference an object that is simply a Car. Or it can reference an object that is a more specific type (a subtype) of Car. For example, a Car variable might reference an instance of "Volkswagen," which IS-A Car.

The compiler only knows the types of references. It doesn't know the true runtime type of an object. So when you say...

SuperType sup = new SubType();

...that's fine. Because "new SubType()" returns a reference of type SubType. The compiler knows it's always true that a SubType IS-A SuperType (a Volkswagen is always a Car). So it's okay to assign that reference to a variable of type SuperType. (This is called an "assignment conversion.")

On the other hand, a Car is NOT always a Volkswagen.

SubType sub = new SuperType();

...will fail to compile, because "new SuperType()" returns a reference of type SuperType, and the compiler knows that a SuperType is NOT a Subtype.

But suppose the SuperType reference on the right side did, in fact, point to an instance of SubType. For example...

SubType sub = sup; //using the sup we assigned above

To assure the compiler that this assignment is valid, the programmer must insert an explicit cast to downcast the SuperType reference (sup) to type SubType...

SubType sub = (SubType)sup;

With the explicit cast, the compiler will trust the programmer in saying that the object referenced by sup is, in fact, a SubType object. In this example, there is no problem at runtime, because the true runtime type of the object referenced by "sup" is SubType.

But if it turns out that the downcast is not correct, then the program will fail at runtime with a ClassCastException. This is what's happening with...

SubType sub = (SubType) new SuperType();

"new SuperType()" creates an object with a true runtime type of SuperType, and returns a reference that also has the type SuperType. However, an explicit cast tells the compiler to downcast that reference to SubType, so it compiles. However, at runtime, the program fails because the true type of the object is NOT SubType.
[ November 16, 2008: Message edited by: marc weber ]
 
Pawel Nowacki
Ranch Hand
Posts: 67
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Thanks for reply marc, that was illuminating. But i have one more doubt:
You wrote:



//1.
SuperType sup = new SubType();
SubType sub = (SubType)sup;

//2.
SubType sub = (SubType) new SuperType();



While i understand that 2. is going to compile but throw ClassCastException,
i think that 1. is slightly different from what i wrote in snippet:

SuperClass sup = (SuperClass) new SubClass();
SubClass sub1 = (SubClass) sup;

Or using your notation:
SuperType sup = (SuperClass) new SubType();
SubType sub = (SubType)sup;

This can be transformed to:

SubType sub = (SubType)(SuperClass) new SubType();

Now, from what you wrote, left side is reference of type SubType
and on the right there is SubType object (new SubType()) but what happens
with casting? What is the actual role of cast operator? If by writing this:

(SuperClass)new SubType()

you really say: "trust me, this SubType is really a SuperClass", what about this:

(SubType)(SuperClass)new SubType()

"trust me, this SubType is really a SuperClass, but wait...no it is SubType after all"

so in conclusion, there is no need to say:
SuperType sup = (SuperClass)new SubType;
or
(SubType)(SuperClass)new SubType()

but
SuperType sup = new SubType;
and
new SubType()

, am i right?
[ November 17, 2008: Message edited by: Pawel Nowacki ]
 
marc weber
Sheriff
Posts: 11343
Mac Safari Java
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Originally posted by Pawel Nowacki:
...am i right?


Yes.

Upcasting is changing type by moving up the inheritance hierarchy. This is always safe, because it's always true that a SubType IS-A SuperType (for example, it's always true that a Volkswagen IS-A Car). Therefore, an explicit cast is NOT needed when upcasting.

SuperType sup = new SubType();
...or...
Car c = new Volkswagen();

Downcasting is changing type by moving down the inheritance hierarchy. This is NOT always safe, because it's NOT always true that a SuperType IS-A SubType (for example, it's NOT always true that a Car IS-A Volkswagen). Therefore, an explicit cast IS required when downcasting.

SubType sub = (SubType)sup;
...or...
Volkswagen v = (Volkswagen)c;
 
Greenhorn
Posts: 1
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
In practical terms, what's the best way to deal with turning a sup into a sub? Do I have to clone sup into sub?
 
author and iconoclast
Posts: 24204
44
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

Originally posted by Luca Fabbri:
In practical terms, what's the best way to deal with turning a sup into a sub? Do I have to clone sup into sub?



You can't "turn" an object into any other type; if an object is actually of type "sup", then nothing you can do will make it be a "sub". You'd have to actually create a "sub" object in the first place.

If, on the other hand, a variable of type "sup" is referring to an object that is really a "sub", then all you have to do is assign it to a new variable of type "sub" (with a cast) and you're all set.
 
Marshal
Posts: 77936
373
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
. . . and welcome to JavaRanch
 
Ranch Hand
Posts: 78
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Can someone explain one more time why the compiler only knows the types of the references? And why it does not know the runtime of the Object?

Qoute above:
"The compiler only knows the types of references. It doesn't know the true runtime type of an object."

Thank you,

Arend
 
author
Posts: 23937
142
jQuery Eclipse IDE Firefox Browser VI Editor C++ Chrome Java Linux Windows
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Arend van der Kolk wrote:Can someone explain one more time why the compiler only knows the types of the references? And why it does not know the runtime of the Object?



A compiler runs ... well ... during compile time. And not at runtime. How can the compiler know what will happen during runtime, if the compiler isn't actually running the code?

Henry
 
Campbell Ritchie
Marshal
Posts: 77936
373
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
You do not have values for i until runtime. It is therefore impossible for the compiler to predict what sort of Animal a will be.
 
Arend van der Kolk
Ranch Hand
Posts: 78
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
True, thank you. and the reference type is declared at compile time
reply
    Bookmark Topic Watch Topic
  • New Topic