Why is this allowed:
List<List<?>> list = new ArrayList<List<?>>()
but not this?
List<?> list = new ArrayList<?>(); //Compile error: "Cannot instantiate the type ArrayList<?>"
When you create an ArrayList, you need to define the type of objects that it will contain:
You can not instantiate an object with an unknown generic which is why the second line fails.
List<?> list = new ArrayList<String>();
Would work however when using the "list", the code would not know that it was a String list making it rather useless.
The first invocation works because you specify that you want to create an array list of other lists, what those lists are will be determined when you actually instantiate the child lists. Here you only instantiate the parent list which is effectively a list of lists.
Think of a generic type definition as both
Now lets translate this logic to non-generic variables:
CharSequence val = new String("foo");
is perfectly legal. The variable val
is representing a type (2) and there will of course never be direct instances of the interface CharSequence
. You could however not construct (1) this type, but you can assign a assignable subtype to it such as a String
. You could neither replace the creation of a string by stating something like new [? extends CharSequence]
, you need to explicitly name the type to be constructed.
Now let's head back to generics where things are similar. When you call a constructor of a generic type.
new ArrayList<List<?>>()
you are in a way constructing (2) a new "type instance" of a generic type where you need to explicitly assign a value to the type variable T
of the generic definition in ArrayList<T>
. ?
is by itself not describing a Java type and can therefore not be used as an assignment value. However, other than T = ?
, the definition T = List<?>
is possible since the wildcard can be a part of a valid Java type definition.
When using the wildcard in a type definition (1) as in
List<?> list
you are not constructing a new generic type, you are merely describing the bounds of one. Therefore, the wildcard can be used on this occasion.