Consider these following classes:
class A{ }
class B extends A{ }
As we know this compiles fine:
List<? extends A> xx = new ArrayList<B>();
List<? extends List<? extends A>> xy = new ArrayList<List<? extends A>>();
But this gives compile time error
List<? extends A> yx = new ArrayList<? extends A>();
List<? extends List<? extends A>> yy = new ArrayList<? extends List<? extends A>>();
The error says:
required: class or interface without bounds
I'm aware that the fresh values interpreted by the compiler for the above initializations are different, and thus they cannot be cast safely. But what does 'without bounds' means in the above error message?
This error is referring to the creation of the new ArrayList
whose direct, top-level type parameter is using a wildcard. This is not allowed, despite the fact that a nested type parameter is allowed to have a wildcard.
The JLS, Section 15.9, "Class Instance Creation Expressions", states:
If TypeArguments is present immediately after
new
, or immediately before(
, then it is a compile-time error if any of the type arguments are wildcards (§4.5.1).
The key word here is "immediately", because that represents the direct type argument, not the nested type argument.
Here is the restriction mentioned in Angelika Langer's article about generics and its usages:
They [wildcards] can not be used for creation of objects or arrays, that is, a wildcard instantiation is not permitted in a new expression. Wildcard instantiations are not types, they are placeholders for a member from a family of types. In a way, a wildcard instantiation is similar to an interface: we can declare variables of interface types, but we cannot create objects of interface types; the created objects must be of a class type that implements the interface. Similar with wildcard instantiations: we can declare variables of a wildcard instantiated type, but we cannot create objects of such a type; the created objects must be of a concrete instantiation from the family of instantiations designated by the wildcard instantiation.
(emphasis mine)
Basically, a wildcard type is not a concrete type and cannot be instantiated, with similar reasoning to not being allowed to create an instance of interface directly.
However, that says nothing about nested wildcards, which relate to the creation of initially unrelated objects that may eventually be associated with this type. In your example, this would be the nested List
s that may be added to the outer ArrayList
. They could be references to List
s of any matching wildcard type, but they're not being created here.
Summary
Java doesn't allow a wildcard in a instance creation expression (with new
), but it does allow a nested wildcard in such an expression, because a direct wildcard type is not a concrete type.