Search code examples
javacollectionscompilationwildcard

Why does this compile? Java


I was taught that the following compiles:

Collection <? extends T> collection;
List<T> list;
collection = list; // Compiles

With the reason that "that's how Java developers defined it". I would like to know the rationale behind it. It compiles but can make problems during runtime (e.g. we wouldn't be able to add any objects to collection).

Any clarification would be appreciated.

Edit: I am referring to the fact that an Object of generic type ? extends T is pointing to an Object of generic type T. It seems rather counterintuitive.


Solution

  • Edit: I am referring to the fact that an Object of generic type ? extends T is pointing to an Object of generic type T. It seems rather counterintuitive.

    To understand this, you have to understand what exactly a Collection<? extends T> is.

    It is: a Collection with elements of a specific, but unknown type (indicated by the ?) that extends T.

    Note that it is not a Collection of objects of arbitrary (and possibly different) types that extend T (this is a misconception that many developers have about generic wildcards).

    It's perfectly OK that you can assign a List<T> to a variable of type Collection<? extends T>, because List is a subtype of Collection, and the elements of a List<T> are indeed of the type ? extends T. (In this particular case, the actual type is the type T itself, but that still matches "some unknown type ? that extends T").

    Note that using the wildcard actually throws away information about the exact type of the elements of the collection - it makes Java forget the exact type, and only makes it remember that it's an unknown type that extends T.

    You cannot add anything to a collection of a wildcard parameterized type such as a Collection<? extends T>, precisely because the information about the exact type of the elements is missing. If you would try to add an element to such a collection, there's no way for the compiler to check if the type of the element you're adding is the right type.

    If you try to call add() on a Collection<? extends T> you will get a compile error that says that the type of the object you're adding is not of the type "capture of ... of ? extends T". That basically means: "I cannot check that the object you're trying to add is of the unknown type ? extends T".

    The type can also not be checked at runtime because of type erasure: type arguments are a compile-time only thing in Java, at runtime they don't exist anymore so also then there's not enough information to check that the element you're adding is of the right type.