2

When trying to better understand generics, I created two collections with different bounds. Note that I'm not gonna paste the class definitions here as they are self-explanatory. Also, to make things simple, everything is a class (no interfaces here).

List<? super Fruit> list1 = new ArrayList<>();
List<? extends Fruit> list2 = new ArrayList<>();

My understanding is that, list1 is declared as a general purpose fruit container. So it's able to hold any kind of fruit, which is essentially the same as declaring List<Fruit>. I'm able to verify the behavior with:

list1.add(new Apple());
list1.add(new Orange());
list1.add(new Fruit());

However, I'm struggling to comprehend the upper-bounded version of this, which is:

List<? extends Fruit> list2 = new ArrayList<>();

When I try to add items into the list, the compiler gives out errors:

list2.add(new Fruit()); // error
list2.add(new Apple()); // error
list2.add(new Object());// error

The error I got is:

add(capture<? extends Fruit> in List cannot be applied to (Apple)

The real interesting thing is that the following works fine:

List<Juicer<? extends Fruit>> fruitJuicers = new ArrayList<>();
Juicer<Fruit> fruitJuicer = new Juicer<>();
Juicer<Apple> appleJuicer = new Juicer<>();

fruitJuicers.add(fruitJuicer);
fruitJuicers.add(appleJuicer);

Would appreciate it if someone can help me understand the reason behind this.

scabbage
  • 1,112
  • 2
  • 12
  • 24
  • Is that fruit is interface or a class? – Kiran Kumar May 20 '17 at 02:24
  • 1
    Please post the compiler error description as well – Kiran Kumar May 20 '17 at 02:25
  • No interfaces here. I included the compiler error in the post. – scabbage May 20 '17 at 02:48
  • 1
    @Andreas This is *most likely* a duplicate of *some* question. But (@scabbage) pointing out what the *actual* question is might help to narrow it down to a better fitting one. Is the question here specifically *why the `Juicer` example worked*? – Marco13 May 20 '17 at 03:24
  • 1
    Oracle covers this pretty well: https://docs.oracle.com/javase/tutorial/extra/generics/wildcards.html – Gene May 20 '17 at 03:25
  • @Andreas, I agree with Marco13 that the answer you referenced does not fully cover the questions here. In particular, it does not address the aspect related to captures. – Turix May 20 '17 at 03:28
  • @Turix What aspect related to captures? The only "capture" mentioned in the question text is the error message, which is just the compilers way of saying "you can't do this", which is fully covered by the duplicate link: *You can't add any object to List extends T>* It cannot be stated more succinct than that, but let's try: **You can't. It will not compile.** The last code block doesn't use wildcard for the `List` type parameter, only for the `Juicer` type, so it doesn't affect whether you can "produce" or "consume". – Andreas May 20 '17 at 03:37
  • Yup, the duplicate post did answer one of my questions, which is: why I can't add any object to `List extends Fruit>`? As to my second question - why I'm able to add to `List>`, which also uses `extends` and is seemly similar - I think @Andreas answered my question. Thanks! – scabbage May 20 '17 at 03:54
  • @Andreas I agree that the reason that nothing can be added to `list2` is explained very well in the answer you linked, but that doesn't really cover what the compiler is telling him (which is roughly "I don't know what type of list it is, b/c the capture never got resolved"). I.e., I think there was more depth here that could've helped with interpreting compiler messages of that sort... However, it appears he's satisfied so I'll let it go. – Turix May 20 '17 at 04:05
  • `capture extends Fruit> in List cannot be applied to (Apple)` means *"a value of type `Apple` cannot be assigned to a variable with a type that can **any** subclass of `Fruit`"*. Which is true, because "*any* subclass of `Fruit`" could be `Orange`, and you certainly cannot assign an `Apple` to a variable of type `Orange`. – Andreas May 20 '17 at 04:53

0 Answers0