The key to understanding this behavior is understanding what the erasure type really does. Despite the widespread belief that it removes type parameters at run time - in fact, this does not work that way. What he does is he reduces them to the declared parameter boundaries. Therefore, wherever you type List<T> , where T has borders, it actually comes down to List<[lower-bound-of-T]> . And since Object not CharSequence , List<Object> cannot be added to List<T> (since this means at least List<CharSequence> )
Why is this happening? Imagine your Sandbox class has a method that accepts a parameter of type T:
public class Sandbox<T extends CharSequence> { void bar(T param) {
bar(T) can take T and T is all that extends CharSequence , so basically at runtime it works effectively as
void bar(CharSequence param) {
and therefore, it cannot accept simple Object . Therefore, simply existing non-empty lower bound of the parameter limits free discards from ...<Object>
Also, a wildcard type parameter ? may just blow your mind. He tells the compiler something like, "I have no idea what it is, but I'm sure it satisfies all boundaries." Quite strange, including the fact that you can use (almost?) Anything, so it makes it possible
List<Object> bis = Arrays.asList(Integer.valueOf(1)); List<T> result = (List<T>) (List<?>) bis;
So, when it comes to the generic development class, you have to be very careful.
source share