4

I am trying to understand the behavior of lower as well as upper bound wild cards.

Got an issue while trying to compile the below code.

Collection<? extends Object> c = new ArrayList<Object>();
c.add(new Object()); // Compile time error

For figuring out the issue, I simply tried the lower bound wild card as well. Fortunately or unfortunately, code compiles fine but created so many confusion.

Collection<? super Object> c = new ArrayList<Object>();
 c.add(new Object()); // Compiles fine

Can somebody explain me, how these two code snippets are working. It would be great if someone can provide additional examples/links.

Please correct me if I did something wrong above.

Thanks in advance.

Sarun UK
  • 6,210
  • 7
  • 23
  • 48

2 Answers2

6

? means an "unknown type".

Collection<? extends Object> represents a collection of some type of object. This "some type" can be any type that is a subclass of Object or Object itself. Which type exactly? The compiler does not know.

When you try to add a new Object to the collection, you can't. This is because the collection's type is not known. It can be an ArrayList<String>. It can be a HashSet<Integer>. So the compiler says

"What if the collection is ArrayList<String>? You can't put an Object in there!"

Basically, the compiler is too cautious to let you do that.


Collection<? super Object> represents a collection of some type of object. This "some type" can be any type that is a superclass of Object or Object itself. It can only be one thing here - Object, because Object does not have a superclass. That's why you can add a new Object to the collection.

Even if Object has a superclass, you would still be able to add a new Object(). Let's call the superclass of Object MyClass. Now, the collection can either be a collection of MyClass or Object. Whichever it is, you will be able to add an Object to it.

Sweeper
  • 213,210
  • 22
  • 193
  • 313
  • I fully understood the part regarding `Collection extends Object>` and it makes sense. But what is the reason that is *DOES* accept *ANY* `SupersClass` or the `Object` class itself in case of `Collection super Object>`? – Yahya May 22 '17 at 12:43
  • That's just what ? super Object means. If A extends B, you can add B to a collection of A. It's the same thing here. @Yahya – Sweeper May 22 '17 at 12:44
  • @JornVernee oh it's a typo. I mean you can add A to a collection of B. – Sweeper May 22 '17 at 12:51
  • @Sweeper Thanks, I figured out what you meant. I think your last paragraph explains it well enough. But it's tricky to see in your head. – Jorn Vernee May 22 '17 at 12:53
0

Let's change the class type to make it a bit more understandable. Your first example changed to Number

Collection<? extends Number> c = new ArrayList<Number>();

Means that there are ? objects from type Number. So it could be anything that extends Number e.g. Integer, Double, Float, BigInteger etc. So you can not guarantee what kind of Number Object resides in the list since

List<Integer> // only allows Integer
List<Double> // only allows Double
List<Float> // only allows Float

That's why you can not add anything to <? extends Number> because it could be either one of the Lists above.

The other way around is for <? super Number>. This means that every object inside the List is an ancestor of Number. In this case you are allowed to add anything from supertype/type of Number. You guarantee with ? super Number that everything inside is a Number.

But what you can not guarantee is the actual type e.g.

list.get(0); // is a Number, but could be a Integer
list.get(1); // is a Number, but could be a Float
list.get(2); // is a Number, but could be a Double

tl;dr use extends for reading and super for adding.

And here is a graph from the docs https://docs.oracle.com/javase/tutorial/java/generics/subtyping.html

enter image description here

Here is an explanation from Jon Skeet for <? super Number>

https://stackoverflow.com/a/8083260/4467208

Murat Karagöz
  • 35,401
  • 16
  • 78
  • 107