I’m confused by the following code:
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
public class GenericsTest<T extends List> {
public void foo() {
T var = (T) new LinkedList();
}
public static void main(String[] args) {
GenericsTest<ArrayList> gt1 = new GenericsTest<ArrayList>();
gt1.foo();
System.out.println("Done");
}
}
The runtime type of T appears to be java.util.List, regardless of what Type parameter I passed in to the constructor.
So why is the compiler requiring casting to T when assigning var? Shouldn’t it know at compile time that LinkedList is assignable to List?
I understand the code is bogus, and I understand why it worked at runtime even though it looks like it shouldn’t. The part that is confusing to me is why is the compiler requiring me to type (T) when doing the assignment? Yet it compiles perfectly well without the bogus cast.
Presumably, the compiler understands erasure. It seems like the compiler should be able to compile the code without the cast as well.
In a comment the poster asks,
This cast will not fail. But the compiler is warning that this code sets a time bomb ticking to blow up somewhere else with a
ClassCastException.In the example, there’s no reason to use generics, since none of the API uses the type variable
T. Look at a more realistic application of generics.A
ClassCastExceptionis thrown at line 12.ClassCastException, without a cast? The calling code is perfectly correct. The invalid cast, the bug, is at line 4, in the invoked method. But the exception is raised at some time and place far distant.The purpose of Java generics is to assure that code is type-safe. If all of the code was compiled without “unchecked” warnings, the guarantee is that there will be no
ClassCastExceptionraised at runtime. However, if a library you depend on was written incorrectly, as was this example, the promise is broken.