4

I instantiate the following list:

// I am just revising generics again and the following is just cursory code!
List<? super Integer> someList = new ArrayList<Object>();
someList.add(new Object());

The above will not work. I get a compiler error. However, the following works:

List<? super Integer> someList = new ArrayList<Object>();
someList.add(11);

I am aware that you can add objects to a collection which contains an unbounded wildcard, not a bounded wildcard.

However, why does the above not work? An Object is a supertype of an Integer, so why can't I add it?

Joeblackdev
  • 7,217
  • 24
  • 69
  • 106
  • minor term issue: `List super Integer>` is lower bounded wildcard; `List>` is unbounded wildcard. Even though you use unbounded wildcard `List>`, you can't add instance of any type; you can only add `null`. – rosshjb Dec 12 '21 at 08:31

4 Answers4

10

That declares that it's a list of something that's a supertype of Integer, not that the list can contain anything that's a supertype of Integer. In other words, to the compiler, it could be a List<Integer>, a List<Number> or a List<Object>, but it doesn't know which, so you can't add just anything to the List. The only thing you can safely add is an Integer, since that's guaranteed to be a subtype of any type the List could potentially hold.

In other words, the ? represents one type, not any type. It's a non-obvious but important distinction.

Ryan Stewart
  • 126,015
  • 21
  • 180
  • 199
  • I'm not sure I follow your first sentence. So, it can't be a list of Objects *and* Integers. Just one single type? But I am able to add an Integer to the list - in response to the very last part of your answer. – Joeblackdev Mar 09 '12 at 16:45
  • 1
    Oh right. My bad. Since Integer is the boundary and is guaranteed to be a subtype of any type that the List could be, then Integer can be added. No other type can be, though, such as Number, even though it's a supertype of Integer. As for my first sentence, I think you've got it right: a generic wildcard doesn't mean the list can contain objects of multiple types. It means the list contains objects of an unknown type. Since that type *could* be Number, for example, it's illegal to add Objects to the list. – Ryan Stewart Mar 09 '12 at 17:39
  • Updated my answer in accordance with these comments. – Ryan Stewart Mar 09 '12 at 17:41
  • Then why this is not accepting someList.add(integerValue) if it become List extends Number> someList? It could determine the type as Number from the upper bound. – Yadab Sd Mar 20 '23 at 17:13
4

For the variable someList, all the compiler/language has to work with is the static type List<? super Integer>. It's possible that it could have been assigned from a List<Integer>. Obviously, you don't want to add a new Object() to List<Integer>.

You can add null to List<? super Integer>, and you can pass the list to another method that captures the generic type and can therefore move references around the list (method such as, Collections.shuffle).

Tom Hawtin - tackline
  • 145,806
  • 30
  • 211
  • 305
  • I find this odd though. Should you not be allowed to add an Object anyway as it's within the same inheritance hierarchy as an Integer? Or is this more of a subjective assumption - why add an Object to a "list of Integers"? – Joeblackdev Mar 09 '12 at 16:26
  • The problem is that if you have `List super Integer> list = new List()`, you shouldn't be able to add an `Object` to a list that's actually a `List`. It's perfectly objective. – Louis Wasserman Mar 09 '12 at 17:45
  • But I don't have a List super Integer> list = new List(). I have List super Integer> list = new ArrayList() – Joeblackdev Mar 09 '12 at 17:54
  • 1
    @Joeblackdev Java is a statically-typed language. What you can do to an object is determined by its static type (though the behaviour may be dynamic). – Tom Hawtin - tackline Mar 09 '12 at 17:58
2

A List<? super Integer> is not a list which contains any elements of any supertype of Integer (which also makes no sense), but a list a concrete unknown element type which is a supertype of Integer. So the compiler has no chance to determine, if the element to be added is of the right concrete type.

Any Collections with wildcards in the element type are per se not extendable, but they are modifiable (you may remove an element or clear the whole list).

Arne Burmeister
  • 20,046
  • 8
  • 53
  • 94
2

When the compiler hits someList.add(new Object()), it doesn't remember how you instantiate someList. All information the compiler has is how someList is declared, i.e List<? super Integer> someList. Since you may instantiate someList by either

someList = new ArrayList<Object>()

or

someList = new ArrayList<Integer>()

and the compiler doesn't know which one it is, hence the compiler doesn't allow you to do someList.add(new Object()) because someList might be a List<Integer>.

Bob Wang
  • 606
  • 4
  • 8