Why is this code valid
ArrayList<?>[] arr = new ArrayList<?>[2];
but the following two are not?
ArrayList<? extends Object>[] arr = new ArrayList<? extends Object>[2];
ArrayList<? super Object>[] arr = new ArrayList<? super Object>[2];
The two last rows generate the compile error;
error: generic array creation.
Please clarify difference.
On the other hand ArrayList<?>[] arr = new ArrayList<?>[2];
compiles good but
ArrayList<?> arr = new ArrayList<?>();
not.
both bounded and unbounded wildcards provide a lot of flexibility on API design especially because Generics is not covariant and List<String> can not be used in place of List<Object>. Bounded wildcards allow you to write methods that can operate on Collection of Type as well as Collection of Type subclasses.
What is the difference between a wildcard bound and a type parameter bound? A wildcard can have only one bound, while a type parameter can have several bounds. A wildcard can have a lower or an upper bound, while there is no such thing as a lower bound for a type parameter.
The unbounded wildcard type is specified using the wildcard character (?), for example, List<?>. This is called a list of unknown type. There are two scenarios where an unbounded wildcard is a useful approach: If you are writing a method that can be implemented using functionality provided in the Object class.
An unbound generic type is not itself a type, and cannot be used as the type of a variable, argument or return value, or as a base type. The only construct in which an unbound generic type can be referenced is the typeof expression (§11.7. 16).
There are a few issues going on here, lets look at each in turn:
A type bound (ie extends Object
) can only be declared when declaring a type, it cannot be used when instantiating an object.
for example
ArrayList<? extends Object> ab = new ArrayList<? extends Object>(); // error
ArrayList<? extends Object> ac = new ArrayList<String>(); // okay
Arrays do not support type parameters, for example:
List<Integer>[] arrayOfLists = new List<Integer>[2]; // compile time error
List<Integer> list = new List<Integer>(); // okay
Oracle documents the reasons for this limitation here.
<?>
can be used when declaring a type parameter, and with arrays. It was added to help avoid 'unchecked exception' errors when mixing Java code that does and does not use generics. It means 'unknown generic type'. More detail on unbounded wild cards here.
ArrayList<?>[] arr = new ArrayList<?>[2];
is valid for the reasons outlined above. However it is of very limited use because only null can be assigned to types declared as <?>
.
arr[0] = null; // compiles
arr[1] = new Object(); // compile time error
Oracle provides the following Guide on using wildcards which will help to understand when to use this wild cards.
<?>
cannot be used to instantiate an object. For example
ArrayList<?> arr = new ArrayList<?>(); // does not compile
ArrayList<?> arr2 = new ArrayList<>(); // but this does
ArrayList<?> arr3 = new ArrayList<String>(); // and so does this
However one still has the problem that using <?>
only accepts null.
arr3.add( " " ); // does not compile even though it was instantiated with String
arr3.add( null ); // compiles just fine
You have to first understand why creating an array of a parameterized type is not allowed. It's because arrays check at runtime that elements inserted are instances of the component type (a la instanceof
). It is not possible to check instanceof
a parameterized type, because an object does not have a sense of the type parameter with which it was created. instanceof ArrayList<Integer>
is illegal in Java, as is something like instanceof ArrayList<? extends Number>
, but instanceof ArrayList<?>
is allowed in Java because it needs no information about the type parameter of the object. (By the way instanceof ArrayList<? extends Object>
and instanceof ArrayList<? super Object>
are also illegal.)
Conceptually, ArrayList<? extends Object>
is almost completely identical to ArrayList<?>
(there are minor differences but not relevant), but for consistency of the grammar, new ArrayList<? extends X>[...]
is not allowed for any X.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With