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.