• 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
  • Tim Cooke
  • Liutauras Vilda
  • Jeanne Boyarsky
  • paul wheaton
Sheriffs:
  • Ron McLeod
  • Devaka Cooray
  • Henry Wong
Saloon Keepers:
  • Tim Holloway
  • Stephan van Hulst
  • Carey Brown
  • Tim Moores
  • Mikalai Zaikin
Bartenders:
  • Frits Walraven

Java type casting | OCP certification

 
Ranch Foreman
Posts: 38
5
MySQL Database Java
  • Likes 2
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Hi

I'm prepairing for the OCP certification examination

Today, I encountered the following type casting scenario:



On the above mentioned comment line-->my assumption is as List and Set types are not related by
class hierarchy; compiler should not allow it to compile and throw a compile time error like incovertible types. since variable list
is of type List which is not related to Set type by class hierarchy [Parent-child relationship, child-parent relationship or same type].
So, I assume List type reference variable can't be cast as Set type at compile time.

Similarly, the following code snippet is throwing ClassCastException at runtime:


My same logic: List and Thread types aren't related by parent -child class hierarchy. so, the code shouldn't compile.
but the compiler is letting it compile and ClassCastexception is thrown at runtime like in above mentioned case of List and Thread.

However, if I make the following code changes in above two code snippets:
1.
and
2.
then the outputs are following respectively:
1.
and
2.

Please provide your guidance regarding where are the gaps in my knowledge of type casting in java.

Thanks
 
Saloon Keeper
Posts: 10929
87
Eclipse IDE Firefox Browser MySQL Database VI Editor Java Windows ChatGPT
  • Likes 1
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
GPT:
in this java snippet, how come compiler doesn't complain about the cast?
The Java compiler does not complain about the cast from List to Thread in your snippet because of how raw types and unchecked casts are handled. Here's an explanation:

   Raw Types: The List you created is a raw type because you didn't specify a generic type parameter. Raw types are a backward compatibility feature from before Java introduced generics in Java 5.

   Unchecked Casts: When you use raw types, the compiler allows you to perform unchecked casts. This means that you can cast a raw type to any other type without the compiler issuing an error. Instead, the compiler issues an unchecked cast warning, but it still allows the code to compile.
 
Master Rancher
Posts: 5060
81
  • Likes 3
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
No - this issue is not dependent on raw types.  To demonstrate this, you can add a "<String>"  after every List or Set in the examples, and the results will be almost the same.  You will no longer get the raw types warning, but you will still compile the first two, and get a compile error on the third.  Why is that?

It actually depends on whether the types you are dealing with classes or interfaces, and on whether the classes in question are final.

In the first example, variable "list" has declared type List, and it is being cast to a Thread?  Is this possible?  Not usually, you would think... except that List is an interface.  And Thread is not a final class.  Which means that it is theoretically possible that a variable with declared type "List" might hold a reference to some class that extends Thread, and also implements List.  Such a design might be, well, stupid, but it's possible to do such a thing.  

And even though we can clearly see that no such class is present in the code shown, it doesn't matter.  The rules for casting depend only on the declared type of the thing you're casting (variable "list" in this case, whose declared type is List), and on the type you are casting it to.  They do not depend on anything else you may be able to figure out about what the variable really refers to, no matter how obvious that information is.  So, it doesn't matter that the variable "list" in this code actually refers to an ArrayList specifically.  It matters only that the declared type is List, and that it's possible for that to be cast to Thread, because it's possible that there's a subclass of Thread that also implements List.  

At least at compile time, that's all that matters.  At run time, when the cast is executed, the JVM determines that the variable "list" actually references an ArrayList, not any subclass of Thread.  So the cast fails with a ClassCastException.

Similar logic can be applied to the other two examples.  Why does one compile, while the other does not?  Try to think why one should be theoretically possible, while the other is not.
 
Dalvir Singh Bains
Ranch Foreman
Posts: 38
5
MySQL Database Java
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Thanks @Mike simmons and @Carey Brown for your insights on my post. I really appreciate your time looking into it.

I understood a fairly important knowledge gap about java type casting based on both of your inputs.

@Mike Now, I get it. since ArrayList is a concrete class. So, at compile time compiler is certain that there is no feasibility that, in future, there will be an arbitrary runtime subclass instance extending both ArrayList in this example and Thread class can exist (no multiple inheritance of classes in java). Hence, compiler catches this error at compile time.

while in the case of second last example like this:



compiler at compile time is aware of the possibility that list reference variable of type ArrayList can hold  an arbitrary runtime instance  extending  ArrayList and implementing Set interface in this example. So, that runtime instance will exhibit parent-child relationship to Set type in this cast expression. RESULT--->compiler allows the cast at compile time in this case but JVM throws a ClassCastException

@Carey I'm still trying hard to understand unchecked casts. I need to work more on it. Mixing generic and non generic java code is an important concept.

Please provide your insights on my above mentioned understanding about type casting.

Thanks
 
Carey Brown
Saloon Keeper
Posts: 10929
87
Eclipse IDE Firefox Browser MySQL Database VI Editor Java Windows ChatGPT
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
My apologies for not catching GPT inaccuracy. I had a long discussion with GPT, disagreeing with a number of it's points. After several go-arounds it finally said:

The type system allows the cast because List is an interface and can theoretically be implemented by any class, although it is unsafe.

(why didn't you say so in the first place?)
 
Mike Simmons
Master Rancher
Posts: 5060
81
  • Likes 3
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Carey Brown wrote:[channelling ChatGPT]: Unchecked Casts: When you use raw types, the compiler allows you to perform unchecked casts. This means that you can cast a raw type to any other type without the compiler issuing an error. Instead, the compiler issues an unchecked cast warning, but it still allows the code to compile.


Aside from being irrelevant to the actual problem, this is not true and should be ignored.  When you mix raw types and generics, the compiler will ignore some of the checking that it would otherwaise do - but not all of it, not by a long shot.  You can still get compiler errors from the cast - as you do in the third example from the original post.  

Specifically, when you mix a raw type and a generic type (e.g. by attempting to cast one to the other), the compiler issues a parsning, and also performs type erasure on the generic type.  This means it ignores the generic part of the type, but not the non generic part.  So it basically ignores everything inside < >.  A List<String> will be treated as a raw List.  A Map<Integer,List<String>> will be treated as a raw Map.  So the compiler ends up ignoring some of the information, but not all of it. If the compiler determines that a cast is impossible, based on the raw types after the generic parts are erased, then a compiler error is still possible.
 
Dalvir Singh Bains
Ranch Foreman
Posts: 38
5
MySQL Database Java
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Thanks Mike for further elaboration on casting in case of using generic and non-generic code. I've spent some time practising and understanding casting of interfaces since I posted this question.

Things are crystal clear to me now on this concept. Moreover, I've gone through the details of JEP 409 (Sealed types in java) and looked at this concept from another new dimension.

All the effort was worth. Java has evolved a lot from Java 8 to Java 17:)
 
We should throw him a surprise party. It will cheer him up. We can use this tiny ad:
Gift giving made easy with the permaculture playing cards
https://coderanch.com/t/777758/Gift-giving-easy-permaculture-playing
reply
    Bookmark Topic Watch Topic
  • New Topic