Consider the following snippet:
Integer a = Integer.valueOf(23);
Double d = (Double) (Number) a; //not unchecked cast
List<String> stringList = new ArrayList<>();
List<Integer> integerList = (List<Integer>)(List<?>)stringList; //unchecked cast
- From what I understand - whenever we convert
Supertype -> SubtypeUnchecked cast is flagged as the compiler does not know until the runtime if the type represented by theSupertypewill ever match theSubType. - Then over here - why is
(Double) (Number)anot being flagged as theUnchecked Cast?
That is incorrect. Not even the runtime knows whether your list is a
ArrayList<String>or aArrayList<Integer>. As far as the runtime is concerned, your list is anArrayList(This is because of type erasure). This is why casting aList<?>to aList<String>cannot be checked by the runtime. The runtime does not know what aList<String>is - it only knows aboutList. To the runtime, no checks are needed, since you are just casting fromListtoList, which always succeeds. In fact, nothing is done for this cast at runtime - it is a completely unchecked cast.As a result, this code runs without throwing an exception:
It will throw an exception, however, if you did:
Now, you are getting an integer out of the list, and doing some integer-specific operations to it. But the list contains
"foo", which isn't an integer. The compiler inserts an implicit cast to castintegerList.get(0)toInteger, and that cast failed. Note that this is a checked cast, because the runtime knows about the typeInteger.The cast from
NumbertoDoubleis also checked, because the runtime knows aboutDouble.Side note: there are also "partially unchecked casts", which are things like casting from
ObjecttoArrayList<String>. The runtime can check whether theObjectis anArrayList, but it cannot check whether it is an array list of strings.See all the rules for what is checked and what is unchecked here.