• Post Reply
  • Bookmark Topic Watch Topic
  • New Topic

ClassCastException versus a Inconvertible Types compiler error

 
Chad Michaels
Ranch Hand
Posts: 42
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
OK, for some reason, this one keeps giving me fits. And for obvious reasons, it could boil down to either an exam answer of "Compilation fails" or a "Runtime Exception". In short, is there any telltale way to determine 100% of the time which of the two problems will occur? I keep playing around with this one, but can't seem to get it straight in my mind. Sometimes I'm expecting one, but get the other... and vice versa. What's the deal???
 
Deepak Bala
Bartender
Posts: 6663
5
Firefox Browser Linux MyEclipse IDE
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
A class cast occurs when you tried to cast something at runtime, whose type is not what you thought it would be. When you cast, you are telling the compiler - 'Hey compiler, case my Animal to Dog. I know that at runtime it could even be a Cat but I am pretty darn sure that we will get a Dog.' If at runtime the JVM finds that the Animal was say an Elephant, it will throw a ClassCastException.

In-convertible types is a scenario where the compiler knows for sure that the types in question cannot be converted. This is because they are no where near each others hierarchies. For example



Integers and String have no relation. The only have a common parent - Object. So the compiler knows there is no way this assignment will work. Also, you cannot cast this since the compiler *still* knows that it wont work.
 
Deepak Bala
Bartender
Posts: 6663
5
Firefox Browser Linux MyEclipse IDE
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
oh and welcome to javaranch Chad
 
Chad Michaels
Ranch Hand
Posts: 42
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Well thank you very much Deepak.... very nice of you

So, I read what you wrote, and I wanted to make things a bit more difficult to see. I don't think I accomplished my goal, but here is what I came up with. Let's say you have 3 classes, HumanTransporter, then class Car and class Boat both extend from it.

class HumanTransporter{ }
class Car extends HumanTransporter{ }
class Boat extends HumanTransporter{ }

...somewhere in main....
HumanTransporter ht = new HumanTransporter( ) ;
Boat b = new Boat( ) ;
// Car c = ( Car )b ; // If you UNcomment this line, it creates a compiler inconvertible types error.

ht = new Car( ) ;
Boat bb = ( Boat )ht ;

Now, what's special about this code I created? If you compile it without the commented lines, it will first give you an inconvertible types error due to the Boat and the Car. However, if re-comment the stated line, and get the code to compile, you then get a ClassCastException "Car cannot be cast to a Boat". BUT: This is my point! If the ClassCastException states the "car cannot be cast to a boat", why did this same infaction get caught by the compiler on the other line above?
 
Matthew Brown
Bartender
Posts: 4568
9
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
The difference is the reference type.

In the line you've commented out, b has the reference type Boat. So the compiler knows that b is a Boat. And since a Boat cannot possibly be a Car, the cast cannot possibly work.

In the later case, ht has the reference type HumanTransporter. Although you've assigned a Car to it, the compiler still thinks of it as a HumanTransporter. So it thinks the cast to a Boat might work, and allows it to compile. Then you get the exception when the VM realises it isn't a Boat.
 
Chad Michaels
Ranch Hand
Posts: 42
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Thanks Matthew! That was a perfect explanation, and really helped clear it up for me!
 
Unmesh Chowdhury
Ranch Hand
Posts: 45
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Matthew is correct. Actually, compiler always thinks about the reference variable type. And JVM thinks about the actual object type on the heap which is referenced by the reference variable, and it is true in the case of casting and runtime polymorphism.

Compiler throws inconvertible error for casting if there is no inheritance relationship between the specified references. In your case there is no inheritance relationship between the Boat and Cat, they are just peer to each other.

But, in the case of HumanTransporter and Boat there is an inheritance relationship between the specified reference types. Thus, compiler doesn’t throw the inconvertible error. In this latter case, JVM will throw a ClassCastException since HumanTransporter type reference variable doesn’t refer any Boat type or its subtype object on the heap at runtime to cast into Boat type.
 
Chad Michaels
Ranch Hand
Posts: 42
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Unmesh, thanks for taking it further with the explanation. So from what I understand, the compiler just looks to see if the cast is possible (according to the hierarchy of the referency type and the cast type), and leaves it up to the JVM to check if the cast actually worked? If so, that makes it much easier to understand.
 
Smriti Lath
Greenhorn
Posts: 4
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Hi,

Taaking the same issue further, in the following example why is a casting exception returned instead of a compile time error -



in this case neither class Boat nor its base class Transporter is related to the interface Drivable. Should this return a compile time error?
 
Ankit Garg
Sheriff
Posts: 9528
33
Android Google Web Toolkit Hibernate IntelliJ IDE Java Spring
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
If there are interfaces involved, then generally you can runtime exceptions instead of compile time errors. When you typecast from a class to an interface or from an interface to a class (non-final class to be precise), the cast is allowed at compile time.

Here (1) and (2) are allowed at compile time but (3) is not. This is because of the way the compiler works as everyone said, it looks at reference types. So the new Whatever part is only visible to the compiler at that statement not after that. So basically this is how the compiler looks at it

Now in this situation (1) and (2) are allowed because there might be a class ComplexClass extends PlainClass implements PlainInterface. So the compiler assumes pc and pi might be actual objects of that class. This is why these casts are allowed at compile time. For (3), there cannot be a class which extends both PlainClass and PlainInterfaceImpl so the cast can never succeed at runtime. This is why the compiler alerts you...
 
  • Post Reply
  • Bookmark Topic Watch Topic
  • New Topic