difference between creation unbounded and bounded wild card type array?
Asked Answered
D

2

9

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.

update

On the other hand ArrayList<?>[] arr = new ArrayList<?>[2]; compiles good but

ArrayList<?> arr = new ArrayList<?>();

not.

Defer answered 1/10, 2014 at 10:54 Comment(0)
R
13

There are a few issues going on here, lets look at each in turn:

  1. 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

  2. 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.

  3. <?> 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.

  4. <?> 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

Ringnecked answered 1/10, 2014 at 12:9 Comment(12)
+1 - I hadn't considered the interaction with arrays. Only the type declaration itself.Chartreuse
Perhaps the first question should be, why does the following not compile: - no, I know itDefer
@Defer I'm sorry, I did not follow you. What did you mean?Ringnecked
@Defer ping me when you have had a chance to absorb, I can work in any clarifications. The key point though is this, 'Java does not support generic arrays'. Period. Having ArrayList<?>[] work was in some ways a red herring, and it exists as a special case to integrate code that uses generics with code that does not.Ringnecked
The following is an excellent tutorial: docs.oracle.com/javase/tutorial/java/generics/index.htmlRingnecked
@Chris K ArrayList<?> arr = new ArrayList<?>; it doesn't compile without arrays brackests.Defer
@Defer please recheck, I think that I got caught out by stackoverflows auto formatting. I have added quotes to stop it formatting out the java syntax.Ringnecked
@Chris K did not understand the causal relationship after word ThusDefer
@Defer I have removed the word 'thus', and made a sentence tweak to make it clearer.Ringnecked
@Chris K my current opinion: in general unbounded wild card doesn't limit type thus array shouldn't check type before element adding for example to the array thus we cannot get ArrayStoredException. But bounded wild card limit type thus because we use array we should to know this type in runtime but it is impossible for generics.Defer
@Chris K What do u think about this?Defer
@Defer I think that you are pretty much there. However an unbounded wild card does not mean 'doesn't limit type', it means 'unknown type'. There is a difference. As for arrays should know type at runtime, yes a language can be designed to know. However as I think you said by 'impossible for generics', Java does not support that behavior. In general Java Generics are a big bag of trade offs, mostly pragmatic ones.Ringnecked
A
3

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.

Apps answered 2/10, 2014 at 10:27 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.