5

Lets research some generic instantion situation using wild card:

1

This code

List<?> list = new ArrayList<?>();

generates following error:

required: class or interface without bounds
found:    ?

2

But this

List<?> list = new ArrayList< Set<?> >();

compiles succesfully.

3

and this:

List<Set<?>> list = new ArrayList< Set<?> >();

compiles succesfully too.

4

but this:

List<Set<Map<?,?>>> list = new ArrayList< Set<Map<String,String>> >();

generates

required: List<Set<Map<?,?>>>
found:    ArrayList<Set<Map<String,String>>>

5

List<Set<?>> list = new ArrayList< HashSet<?> >();

generates

required: List<Set<?>>
found:    ArrayList<HashSet<?>>

I am very confusing about these outputs.

I see following regularity:

I can replace ? from left part on right part only on first level and types should be same inside <> and just ? and ? is forbid.

But I don't understand why?

Can you provide common rules how to instantiate generics using wild card?

gstackoverflow
  • 36,709
  • 117
  • 359
  • 710
  • 3
    possible duplicate of [difference between creation unbounded and bounded wild card type array?](http://stackoverflow.com/questions/26139725/difference-between-creation-unbounded-and-bounded-wild-card-type-array) – Alboz Oct 01 '14 at 16:52
  • 1
    @Alboz mentiones question about array!!! current question doesn't related with array!!! – gstackoverflow Oct 01 '14 at 16:57
  • 1
    it's the same reason! – Alboz Oct 01 '14 at 16:59
  • 1
    Thus it is not duplicate! – gstackoverflow Oct 01 '14 at 16:59
  • Ok let's say you can find the answer in that thread, well explained, even if the question is different :). – Alboz Oct 01 '14 at 17:08
  • @Alboz mmm Your answer to that question was not very highly regarded – gstackoverflow Oct 01 '14 at 17:12
  • I didn't send you to my answer, but to the thread. Anyway my answer was the base for the guy who gave the best answer. You can read his comment :) – Alboz Oct 01 '14 at 17:13
  • lol. I just noticed that you are the same person that asked the other question.. I didn't know this. It seems you repeat questions only to get credit for doing "clever questions". Why would you duplicate it if you got a complete answer like that? – Alboz Oct 01 '14 at 17:20
  • 1
    @Alboz I don't know what do you want to achieve but this question absolutely another! – gstackoverflow Oct 01 '14 at 17:27
  • I don't want to achieve anything... But you're repeating questions by changing the data structure, the concepts are the same. You got the answer there. read it, use your brain to understand it. Stop repeating questions in order to get credit... You asked it today not 2 years ago.. – Alboz Oct 01 '14 at 17:29
  • 1
    @Alboz be more polite, please – gstackoverflow Oct 01 '14 at 17:33
  • @Alboz He's right, this is not the same question – johnnyodonnell Sep 16 '19 at 14:44

2 Answers2

3
  1. You cannot use wildcards to instantiate a type directly. The type argument needs to be an actual type when instantiating, so this generates a compiler error.

Code:

List<?> list = new ArrayList<?>();
  1. The following compiles successfully.

Code:

List<?> list = new ArrayList< Set<?> >();

You can use a wildcard as a generic type parameter to a type argument, e.g Set<?>, a set of anything. Also, any type argument will match the wildcard ? on the left.

  1. This compiles successfully also:

Code:

List<Set<?>> list = new ArrayList< Set<?> >();

The type arguments match, and ? isn't used directly as in (1) above.

  1. The following doesn't compile:

Code:

List<Set<Map<?,?>>> list = new ArrayList< Set<Map<String,String>> >();

This is because even though a Map<String, String> is a Map<?, ?>, a List<Set<Map<String, String>>> is not a List<Set<Map<?, ?>>>. Java generics are invariant, meaning that type parameters must match; the "is-a" relationship must be specified explicitly with wildcards in upper bounds. E.g. this change compiles, by introducing upper bound wildcards on the left side.

List<? extends Set<? extends Map<?,?>>> list = new ArrayList< Set<Map<String,String>> >();
  1. This following doesn't compile for the same reason as in (4) above:

Code:

List<Set<?>> list = new ArrayList< HashSet<?> >();

Even if a HashSet<?> is a Set<?>, because of Java's invariant generics, an ArrayList<HashSet<?>> is not a List<Set<?>>. Introducing wildcards on the left as upper bounds works here too:

List<? extends Set<?>> list = new ArrayList< HashSet<?> >();
rgettman
  • 176,041
  • 30
  • 275
  • 357
2
  1. You can't instantiate with a wildcard. You have to specify the type. "?" isn't a type.
  2. This is okay, because you're giving List<?> a type, which is Set<?>. Set<?> is a type.
  3. Correct. ArrayList<T> is a subtype of List<T>.
  4. This is where things get ugly. The right hand is not a subtype of the left hand, because of the screwy way that Java deals with type parameters. The type parameters have to match exactly, or you have to use covariance/contravariance (the <A extends B> or <A super B> stuff). List<String> is not a subtype of List<Object>. It is a subtype of List<? extends Object> or just List<?>.
  5. Same as above. If you had declared it as List<? extends Set<?>> it would work.
MattPutnam
  • 2,927
  • 2
  • 17
  • 23
  • *"`ArrayList` is a subtype of `List`"* No, `ArrayList` **implements** `List`. – user1803551 Oct 01 '14 at 17:10
  • Java is not screwey with respect to how it handles case 4 or 5. It is completely consistent. If the type of `list` is `List>>`, then it is acceptable for me to append to a `Collections.singleton(Collections.SingletonMap(new Object(), new Object()))`. But that element is not acceptable for an object whose type is `ArrayList>>`. It is therefore not type-safe to assign an object of the latter type to a variable having the former type. – John Bollinger Oct 01 '14 at 17:12
  • 1
    @user1803551: since you can assign an `ArrayList` to a `List` there *is* a subtype (IS-A) relationship. Not sub*class*, but sub*type*. – Jan Van den bosch Oct 01 '14 at 17:47
  • @JanVandenbosch I had to check the JLS for that. According to 4.10, `ArrayList` is a subtype of `List` only if `List` is a supertype of `ArrayList`. According to 4.10.2, the supertypes of `ArrayList` would be a **superclass** of `ArrayList` or the raw type `ArrayList`. These do not include `List`. I do not think "is-a" is the same as "subtype". – user1803551 Oct 01 '14 at 18:40