| Author |
Confused on ClassCastException
|
Rajiv Rai
Ranch Hand
Joined: Jun 14, 2010
Posts: 57
|
|
In the above java code , the commented statement throws a ClassCastException if it is uncommented and run..
As per my understanding , the last line of code should also throw ClassCastException due to the same reason for which the
exception is thrown on the commented statement..
but the last line executes and does not throw any exception..
Folks, Please tell me where is my understanding wrong
Thanks
|
 |
Nam Ha Minh
Ranch Hand
Joined: Oct 31, 2011
Posts: 347
|
|
the line:
actually attempts to down cast a Beta object (x) to a Delta object. Downcasting will cause runtime error.
but the line:
works fine because x is actually a Beta object.
|
Job Offer: Online working Java technical writing
|
 |
Rajdeep Biswas
Ranch Hand
Joined: Mar 26, 2012
Posts: 163
|
|
Nam wrote: Downcasting will cause runtime error
Be careful in what you cast!
|
The biggest gamble will be to ask a question whose answer you know in that it will challenge your theory | www.TechAspire.blogspot.in
|
 |
Rohan Deshmkh
Ranch Hand
Joined: Aug 31, 2012
Posts: 127
|
|
Nam Ha Minh wrote:
but the line:
works fine because x is actually a Beta object.
Foo f = (Alpha)x; will work fine because x is object of Beta[because of Beta x = new Beta(); ]
and Beta is a sublcass of class Alpha.So it's right.
Foo f = (Delta)x; will not work because x is a object of Beta[because of Beta x=new Beta(); ] and Beta is not a sublass of Delta.
Am i correct till now?
Now:
Beta b = (Beta)(Alpha)x;
(Alpha)x is already correct as we saw above.
Now does (Alpha)x mean that x will be treated as if it's an object of Alpha. If it's correct then the expression (Beta)object of Alpha should also cause runtime error as Alpha is not a subclass of Beta.
And if i assume that what i said above is not correct , Now (Alpha) x does not mean that x will be treated as if it's an object of Alpha.Then x is still a object of Beta after (Aplha)x then what's the point of casting, as we are casting it to Beta only.
Also in statements like
Foo f = (Delta)x; or
Foo f = (Alpha)x
Do we also have to consider about the left side of == ?What i am asking is If (Delta)x on right side is wrong in one case then it will wrong in all cases irrespective of the left side.
Sorry guys, I am really confused about casting and it's the only topic due to which i am extending my exam for OCAJP7.I have read about casting on this forum and also in several books, i understand what is being said but this topic has really confused me a lot.
|
 |
Junilu Lacar
Bartender
Joined: Feb 26, 2001
Posts: 4118
|
|
One thing that can get you confused about casting is mistakenly thinking that it changes the actual type of an object, which it doesn't. Casting is simply a way to tell the compiler - "Trust me, I know that this object is going to be compatible with the declared type at runtime."
To clarify what another poster said about downcasting: it can--but not always will--cause a runtime error. The key is assignment compatibility of the runtime type to the cast type. In this case, the runtime type (Beta) must either be the same as the cast type, which it isn't (Beta != Delta), or a subclass of the cast type, which it isn't (Beta is not a subclass of Delta). Since neither of the type requirements are met, then a ClassCastException is thrown. This is the runtime environment saying, "Well, you told the compiler to trust you about the type but after double checking, I found that it's still not right."
|
Junilu - [How to Ask Questions] [How to Answer Questions] [MiH]
|
 |
Tony Docherty
Bartender
Joined: Aug 07, 2007
Posts: 1176
|
|
Foo f = (Delta)x; will not work because x is a object of Beta[because of Beta x=new Beta(); ] and Beta is not a sublass of Delta.
Am i correct till now?
Yes
Beta b = (Beta)(Alpha)x;
(Alpha)x is already correct as we saw above.
Now does (Alpha)x mean that x will be treated as if it's an object of Alpha. If it's correct then the expression (Beta)object of Alpha should also cause runtime error as Alpha is not a subclass of Beta.
Assume you cast 'x' to type Alpha and assign it to variable 'a' which is of type Alpha. If you now use 'a' you can only access members of class Alpha and not any members of class Beta because variables of type 'a' only know about objects of type Alpha (and it's super classes), but the object itself is still of type Beta so you can cast 'a' back to type Beta. You can't cast it to Delta though because the object isn't of type Delta or a sub class of type Delta.
Equally if you had an object of type Delta you could cast to Alpha, Beta and/or Foo and later cast it back to Delta.
Also in statements like
Foo f = (Delta)x; or
Foo f = (Alpha)x
Do we also have to consider about the left side of == ? What i am asking is If (Delta)x on right side is wrong in one case then it will wrong in all cases irrespective of the left side
== means something different to =. I'm not sure what you mean here can you clarify your question.
|
 |
Rohan Deshmkh
Ranch Hand
Joined: Aug 31, 2012
Posts: 127
|
|
Tony Docherty wrote:
== means something different to =. I'm not sure what you mean here can you clarify your question.
Oops , I wanted to say = and not ==.By mistake i typed ==.
I am still not clear with Beta b = (Beta)(Alpha)x;
what will the above line do?I think it's a example of down casting, isn't it? Do we always get runtime error when we downcast?Look's like no , as in the above code runtime exception is not generated.And after this statement is executed which members can be called through instance b.
|
 |
Jeff Verdegan
Bartender
Joined: Jan 03, 2004
Posts: 5895
|
|
Rohan Deshmkh wrote:
Tony Docherty wrote:
== means something different to =. I'm not sure what you mean here can you clarify your question.
Oops , I wanted to say = and not ==.By mistake i typed ==.
I am still not clear with Beta b = (Beta)(Alpha)x;
what will the above line do?I think it's a example of down casting, isn't it?
Variable x is declared as a Beta, so the frist step, casting to Alpha, is an upcast. It's always legal, and it's basically never necessary. (The only time it ever has any effect is if you have overloaded method signatures where one takes the subclass and the other takes the superclass, and you have a reference to the subclass, but you want to call the method that takes the superclass argument. If you ever encounter this situation, you almost certainly have a design problem.)
Then we downcast that reference-to-Alpha expression to a reference-to-Beta. This is always legal at compile time, but it can cause a ClassCastException at runtime. If the object being referenced is not an instance of Beta or a subclass of Beta, you'll get the exception. In this case, since x was declared as a reference to Beta anyway, we know that this problem cannot arise here.
It's important to remember that casting never changes any object in any way. For reference types, it only changes how the compiler or runtime views the reference.
|
 |
Rohan Deshmkh
Ranch Hand
Joined: Aug 31, 2012
Posts: 127
|
|
Ok I am getting little bit.
When the expression involves double casting like:
Beta b = (Beta)(Alpha)x;
Then all we have to do is to check if x is a instance of Beta or if x is a instance of Subclass of Beta.We don't have to care about what's on the left side of = or what's in the middle of (Beta)(Alpha)x .
If it is an instance then it will not give a runtime exception.Am i correct now.
Now assuming that the statement Beta b = (Beta)(Alpha)x; is correct now b can invoke which methods from which class?
I have one more doubt regarding a similar question , so i have opened a new thread:
http://www.coderanch.com/t/593431/java/java/output-Casting
|
 |
Tony Docherty
Bartender
Joined: Aug 07, 2007
Posts: 1176
|
|
When the expression involves double casting like:
Beta b = (Beta)(Alpha)x;
Then all we have to do is to check if x is a instance of Beta or if x is a instance of Subclass of Beta.
Yes, although you would never write code like that. There is no point in double casting something without doing an operation in between. If you think about the line of code above, you are taking x which is of type Beta upcasting it to Alpha and then downcasting it back to Beta and assigning it to b. This is exactly the same as just assigning x to b without any casts.
We don't have to care about what's on the left side of = or what's in the middle of (Beta)(Alpha)x .
No. The variable on the left side of = must be of an appropriate type ie it must be either the type the right side is cast to or a super type of it. Also the bit in the middle must be a legal cast.
Now assuming that the statement Beta b = (Beta)(Alpha)x; is correct now b can invoke which methods from which class?
It doesn't matter what is on the right side of the expression, if you have a variable of type Beta that is non null you can invoke any visible instance method declared in the Beta class and it's super types.
|
 |
Rohan Deshmkh
Ranch Hand
Joined: Aug 31, 2012
Posts: 127
|
|
OK thanks i got it.Very nice explanation @Tony Docherty
Thanks for everyone who cleared my doubts.
|
 |
Jeff Verdegan
Bartender
Joined: Jan 03, 2004
Posts: 5895
|
|
Rohan Deshmkh wrote:Ok I am getting little bit.
When the expression involves double casting like:
Beta b = (Beta)(Alpha)x;
Then all we have to do is to check if x is a instance of Beta or if x is a instance of Subclass of Beta.We don't have to care about what's on the left side of = or what's in the middle of (Beta)(Alpha)x .
Not true.
There are 3 different steps here where type compatibility matters.
1. (Alpha)x : At compile time, the type of x must be a reference that could possibly point to an Alpha. So x has to be declared Alpha, or a supertype of Alpha (class or interface) or a subtype of Alpha (class or interface), or x has to be declared a reference to a non-final class in which case Alpha has to be an interface. If these conditions are met--that is if it's possible that x could point to an Alpha, then it's legal at compile time. Then at runtime, the object that x points to has to actually be an Alpha. That is, the object has to be Alpha or a subclass or superclass[EDIT: Just Alpha or a subclass, not a superclass. Thanks for the correction, Praveen.] of Alpha, or a class that implements Alpha if Alpha is an interface.
2. (Beta)(Alpha)x : In step 1 we casted from x's type to Alpha. Now we're casting from Alpha to Beta. Everything above applies exactly as before, except where we said "x" above we're now saying "Alpha", and where we said "Alpha" we're now saying "Beta".
3. Beta b = (Beta)(Alpha)x : Now we're assigning the reference value to the b variable. So the type of the expression on the RHS must be assignment-compatible with b's declared type, which is Beta. In this case, the cast is telling us that the RHS will be treated as a reference to Beta, so it's legal.
Now assuming that the statement Beta b = (Beta)(Alpha)x; is correct now b can invoke which methods from which class?
To answer that, it doesn't matter what's on the RHS. All that matters is that b is declared as Beta, so b can invoke any accessible methods declared in Beta, or in any superclass or superinterface of Beta, but nothing that's declared only in subclasses.
|
 |
Rohan Deshmkh
Ranch Hand
Joined: Aug 31, 2012
Posts: 127
|
|
@ Jeff Verdegan: yes i understood now.I had no problems during what would happen at compile time after reading your awesome reply at thread http://www.coderanch.com/t/566171/java/java/polymorphism-casting-logic#2572095 in which you explained the concept with diagram.
Thanks..
|
 |
Jeff Verdegan
Bartender
Joined: Jan 03, 2004
Posts: 5895
|
|
Cool! I'm glad you found it helpful! (Although I just copied somebody else's diagram and expanded a bit on the explanation.)
|
 |
Praveen Kumar M K
Ranch Hand
Joined: Jul 03, 2011
Posts: 256
|
|
Jeff Verdegan wrote:
1. (Alpha)x : At compile time, the type of x must be a reference that could possibly point to an Alpha. So x has to be declared Alpha, or a supertype of Alpha (class or interface) or a subtype of Alpha (class or interface), or x has to be declared a reference to a non-final class in which case Alpha has to be an interface. If these conditions are met--that is if it's possible that x could point to an Alpha, then it's legal at compile time. Then at runtime, the object that x points to has to actually be an Alpha. That is, the object has to be Alpha or a subclass or superclass of Alpha, or a class that implements Alpha if Alpha is an interface.
Just this part is not right. You can overrun the compiler by staying in the inheritance hierarchy, but not the jvm.
|
 |
Jeff Verdegan
Bartender
Joined: Jan 03, 2004
Posts: 5895
|
|
Praveen Kumar M K wrote:
Jeff Verdegan wrote:
1. (Alpha)x : At compile time, the type of x must be a reference that could possibly point to an Alpha. So x has to be declared Alpha, or a supertype of Alpha (class or interface) or a subtype of Alpha (class or interface), or x has to be declared a reference to a non-final class in which case Alpha has to be an interface. If these conditions are met--that is if it's possible that x could point to an Alpha, then it's legal at compile time. Then at runtime, the object that x points to has to actually be an Alpha. That is, the object has to be Alpha or a subclass or superclass of Alpha, or a class that implements Alpha if Alpha is an interface.
Just this part is not right. You can overrun the compiler by staying in the inheritance hierarchy, but not the jvm.
Oops, you're right. I must've been tired when I wrote that. I remember staring at it and going back and forth a few times. Thanks for the correction.
|
 |
Rajiv Rai
Ranch Hand
Joined: Jun 14, 2010
Posts: 57
|
|
The line of code where the object of class B is created throws a ClassCastException
at runtime..
I fail to understand why the compiler allows it.
I guess it has got something to do with Dynamic Binding.
Also please let me understand what is dynamic binding in relation with the code I have posted
Thanks
|
 |
Jeff Verdegan
Bartender
Joined: Jan 03, 2004
Posts: 5895
|
|
Rajiv Rai wrote:
The line of code where the object of class B is created throws a ClassCastException
No it doesn't. The line where the A is created does though.
I fail to understand why the compiler allows it.
In the first line, we're creating a B. That means the expression on the RHS is "reference to B". Since B is a subclass of A, every B IS-AN A, so both the compiler and the runtime are happy.
In the second line the result of the new operator it "reference to A". Then we try to cast that to B. Since B is subclass of A, it's possible that a "reference to A" actually points to a B object, so the compiler allows that cast. All it cares about is that the reference is of a type that could possibly refer to a B object (or subtype of B). The compiler doesn't check how that reference got created, since that's a runtime action. As far as the compiler is concerned, new A() is the same as a call to public A method_that_randomly_returns_either_A_or_B() because both evaluate to "reference to A". In the case of the second one, there's no way it could know what type will be returned, so it has to allow the cast. To keep the language simple, the new A() is treated the same way--both are evaluated only by what their compile-time reference type is.
So the comiler says, "Oh, you want to cast an A to a B? That might be possible, since that A reference couuld possibly point to a B object, so I'll allow it." Then at runtime, since we don't point to a B object, we get the exception.
|
 |
 |
|
|
subject: Confused on ClassCastException
|
|
|