I am reading about restrictions on generics from the Java Tutorials, specifically casting with parameterized types. I understand the examples that are presented. However, I am unsure about the following example:
List<? extends Number> l1 = new ArrayList<Integer>();
// unchecked cast warning
ArrayList<Number> l2 = (ArrayList<Number>) l1;
// no unchecked cast warning
ArrayList<? extends Number> l3 = (ArrayList<? extends Number>) l1;
I understand why there is a warning in the first case. Why is there no warning in the second case? Is it because the only operations that I can perform on l3
are safe (e.g., I cannot add (say) a Float
to the list)?
UPDATE: Below is an excerpt from section 5.5.2 of the JLS that addresses similar questions.
A cast from a type
S
to a parameterized type (§4.5)T
is unchecked unless at least one of the following is true:
S <: T
- All of the type arguments (§4.5.1) of
T
are unbounded wildcardsT <: S
andS
has no subtypeX
other thanT
where the type arguments ofX
are not contained in the type arguments ofT
.
There's no warning because the cast doesn't change the generic part of the type. List<? extends Number>
and ArrayList<? extends Number>
have the same type argument. Instead, the cast is a checked cast from List
to ArrayList
.