Reputation: 5742
If a class B
extends class A
, one cannot cast List<A>
to List<B>
(cast 1 below). This makes sense, because if it were allowed, then one could read a B
from the list even if it contained none.
However, in the code below, cast 2 from List<? extends A>
to List<B>
causes a warning. Shouldn't it generate an error for the same reason as before? In the code, the list only contains one object that is an A
but not a B
, and yet it is in a list deemed List<B>
.
package test;
import java.util.LinkedList;
import java.util.List;
public class TypeLowerBoundCasting {
static class A {}
static class B extends A {}
static void method1() {
List<A> listOfAs = new LinkedList<A>();
listOfAs.add(new A());
// List<B> listOfAsAsListOfBs = (List<B>) listOfAs ; // cast 1: compiler error
// B b = listOfAsAsListOfBs.get(0); // that would be bad
}
static void method2() {
LinkedList<A> listOfAs = new LinkedList<A>();
listOfAs.add(new A());
List<? extends A> listOfAExtensions = listOfAs;
List<B> listOfAsAsListOfBs = (List<B>) listOfAExtensions; // cast 2: warning, but compiles
B b = listOfAsAsListOfBs.get(0); // that IS bad; causes a run-time error.
}
public static void main(String[] args) {
method2();
}
}
Upvotes: 0
Views: 243
Reputation: 33895
A List<? extends A>
might be a List<B>
, so you can cast:
List<? extends A> list = new ArrayList<B>(); // lose type information
List<B> result = (List<B>) list; // regain type information
Similar to how you can do:
Object o = "Hello World!"; // lose type information
String s = (String) o; // regain type information
Unfortunately, the first cast is unchecked. But a cast in that place is still a valid option, as you can see.
But a List<A>
can never actually be a List<B>
(unless you abuse raw types), because List<A>
is not assignable from a List<B>
(i.e. List<B>
does not 'extend' List<A>
) so you can't cast:
List<A> list = new ArrayList<B>(); // Only works with: (List<A>) (List) new ArrayList<B>();
Upvotes: 3