Maybe the mistake that's being made, which is something I've admittedly done a ton while dealing with generics, is assuming that when you initialize your set or list or whatever, that the generic code somehow transforms based on the initialization.
For example if there's a class Apple that extends
Fruit you might have:
ArrayList<? super Apple> list = new ArrayList<Fruit>();
Which works fine, but then you might incorrectly think the code is now equivalent to:
ArrayList<Fruit> list = new ArrayList<Fruit>();
But actually the "ArrayList<? super Apple>" part should still be read roughly as "an unknown list that can contain Apples". So we can't even add a Fruit to it, because the compiler thinks that the list could have easily been initialized with "new ArrayList<Apple>()" in which case adding a Fruit wouldn't work (the Fruit could be a banana). So really all the compiler feels its safe to add to the list are Apples, and since it checks reference types adding a "Fruit apple = new Apple()" object won't work unless we explicitly cast it to Apple.