Reputation: 525
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
Supertype -> Subtype
Unchecked cast is flagged as the compiler does not know until the runtime if the type represented by the Supertype
will ever match the SubType
.(Double) (Number)a
not being flagged as the Unchecked Cast
?Upvotes: 0
Views: 655
Reputation: 270995
Unchecked cast is flagged as the compiler does not know until the runtime if the type represented by the
Supertype
will 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.
Upvotes: 2