Win a copy of Kotlin in Action this week in the Kotlin forum!
  • Post Reply Bookmark Topic Watch Topic
  • New Topic

Reference varible Casting.  RSS feed

 
Vishal Kurkure
Greenhorn
Posts: 19
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator

this code compiles fine but when we run the code we get java.lang.ClassCastException why???
 
Peter Muster
Ranch Hand
Posts: 74
5
Eclipse IDE Python Ubuntu
  • Likes 2
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
You get a ClassCastException because Animal is not Dog but Dog is Animal. You try to address your variable animal which is of type Animal as Dog though but Dog extends Animal and could have additional functionality which Animal does not offer so you cannot address an instance of Animal as Dog.

I assume you rather wanted to know why the compiler did not detect this. The short answer is that the Java compiler can not detect all errors and those that are not detected will come up at Runtime. As far as casting is concerned the compiler will detect an attempt to cast to a completely unrelated object (like casting a Date to a String) but it won't detect incorrect downcasts.

I don't know the exact specifications, so if someone could point us to official documentation regarding which casting errors the compiler can detect I'd be grateful.

There are other examples where you can trick the compiler. Imaging the following code excerpts in a method:


This code will give you a compile time error stating that the print line is unreachable.


In this case the compiler will only output a warning telling you the print line is dead code.


This time compiler won't say anything because it's not clever enough to detect that the condition is always true and the print line never executed.

I wouldn't be surprised though if the compiler was clever enough to detect your downcast problem in a later version of Java but there will never be a compiler that can detect every error before the code is compiled, for example when the class to be used is built from an external source (imaging it's constructed via reflection based on a HTTP-response), so in my opinion it's always a matter of how much effort is required to have the compiler detect an error (both in development time as in additional calculation effort for the compiler) versus how useful is it to detect such an error in advance.
 
Vishal Kurkure
Greenhorn
Posts: 19
  • Likes 1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Christian Pflugradt wrote:You get a ClassCastException because Animal is not Dog but Dog is Animal. . . .

Thanks,Awesome explanation.
 
Campbell Ritchie
Marshal
Posts: 55707
163
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Christian Pflugradt wrote: . . . The short answer is that the Java compiler can not detect all errors and those that are not detected will come up at Runtime. . . .I don't know the exact specifications, so if someone could point us to official documentation regarding which casting errors the compiler can detect I'd be grateful. . . .
The compiler is programmed to enforce the Java┬« Language Specification (=JLS). It would be very difficult to predict the runtime type of the Animal object in K's line 7. Even harder like this:-It is programmed on the assumption that when the programmer promises to supply a Dog instance the will provide a Dog instance, not Cat or plain simple Animal. That is what you are doing when you catcast a reference type instance: promising it will be a particular runtime type. There is division of labour between the compiler and the runtime, so the compiler does not check for information available at runtime. Some compilers, e.g. Eclipse's, can predict more runtime information which is why you get the dead code warning. Which compiler gave you that dead code warning?

[edit] I wrote cat when I should have written cast. What a seplling error
 
Winston Gutkowski
Bartender
Posts: 10573
65
Eclipse IDE Hibernate Ubuntu
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Vishal Kurkure wrote:Thanks,Awesome explanation.

Indeed.

It's possibly worth mentioning, however, that you should avoid casting as much as you possibly can - and preferably completely.

Since the advent of generics you should rarely (if ever) have any need to cast, and most of the cases you do will probably involve arrays - which is actually a good argument for using Lists instead.

HIH

Winston
 
Steffe Wilson
Ranch Hand
Posts: 165
12
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Christian Pflugradt wrote: As far as casting is concerned the compiler will detect an attempt to cast to a completely unrelated object (like casting a Date to a String) but it won't detect incorrect downcasts.
I don't know the exact specifications, so if someone could point us to official documentation regarding which casting errors the compiler can detect I'd be grateful.

The source and target of the class cast must be related for the compiler to accept the cast - that means that they must be in the same vertical class hierarchy.
Source ISA Dest or Dest ISA Source

The spec is here, see the first bullet point of 5.5.1: https://docs.oracle.com/javase/specs/jls/se8/html/jls-5.html#jls-5.5.1

In OP's case:
Animal ISA Dog fails the compiler casting check.. but Dog ISA Animal succeeds so the cast is accepted by the compiler.

 
Peter Muster
Ranch Hand
Posts: 74
5
Eclipse IDE Python Ubuntu
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Campbell Ritchie wrote:Which compiler gave you that dead code warning?

Yeah that was Eclipse.
 
Campbell Ritchie
Marshal
Posts: 55707
163
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Typical. Eclipse can give much better error messages than the Oracle/Sun compiler.
 
Fred Kleinschmidt
Bartender
Posts: 560
9
  • Likes 1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Here's a (contrived) case where the cast is proper:

this supposes, of course, that Kangaroo has a method hop() but Animal does not, and Whale has a method swim(), but Animal does not.
 
Peter Muster
Ranch Hand
Posts: 74
5
Eclipse IDE Python Ubuntu
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Fred Kleinschmidt wrote:Here's a (contrived) case where the cast is proper:

this supposes, of course, that Kangaroo has a method hop() but Animal does not, and Whale has a method swim(), but Animal does not.

I think most of the time something is wrong with the design if you have to use casts in combination with instanceof. Also if you have multiple projects that use Animals but not all Animals are known or used in each project, instanceof might give you troubles if you expect in a shared class that a certain class exists (ClassDefNotFoundError). I'm speaking from experience since I actually made that mistake in a similar situation.

You might use an enum to identify the concrete type.

With the fragments above you could check if an animal is a whale while avoiding instanceof. Of course you would still have to cast to Whale. A better solution might be to abstract the action that the animal performs. If you had an enum Behave with the constants HOP and SWIM your code could look like this:

If the action is not supported by your animal because someone tries to invoke animal.behave(Behave.HOP) on a Whale you could still throw an UnsupportedOperationException or UnsupportedBehaviourException. ;-)
 
Don't get me started about those stupid light bulbs.
  • Post Reply Bookmark Topic Watch Topic
  • New Topic
Boost this thread!