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?
Advertisement
Answer
Unchecked cast is flagged as the compiler does not know until the runtime if the type represented by the
Supertypewill ever match theSubType.
That is incorrect. Not even the runtime knows whether your list is a ArrayList<String> or a ArrayList<Integer>. As far as the runtime is concerned, your list is an ArrayList (This is because of type erasure). This is why casting a List<?> to a List<String> cannot be checked by the runtime. The runtime does not know what a List<String> is – it only knows about List. To the runtime, no checks are needed, since you are just casting from List to List, 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:
List<String> stringList = new ArrayList<>();
stringList.add("foo");
List<Integer> integerList = (List<Integer>)(List<?>)stringList;
System.out.println(integerList.size());
It will throw an exception, however, if you did:
List<String> stringList = new ArrayList<>();
stringList.add("foo");
List<Integer> integerList = (List<Integer>)(List<?>)stringList;
System.out.println(integerList.get(0) - 1);
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 cast integerList.get(0) to Integer, and that cast failed. Note that this is a checked cast, because the runtime knows about the type Integer.
The cast from Number to Double is also checked, because the runtime knows about Double.
Side note: there are also “partially unchecked casts”, which are things like casting from Object to ArrayList<String>. The runtime can check whether the Object is an ArrayList, 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.