So, what's the difference between these? Well, suppose
bar(List<? extends B> list);
tor(List<? super B> list);
Bhas a subtype
C, and a supertype
A. So the inheritance hierarchy goes
A -> B -> C. You can call
List<B>, but not a
List<C>. But you can call
List<C>; as well as
List<B>. You can call
List<B>. Keep in mind that the contents of the list are not what I am talking about, just the compile-time type of the list.
Generics are a bit more complicated than most people assume. Almost anyone who has spent time with Generics has gotten into several puzzling situations that they can't explain, and where the solution isn't obvious.
The question I wonder about is whether it has done more harm than good. This is not a matter of opinion, I think. If we could count up all the hours of lost productivity in wrestling with generics, and count the hours saved by catching bugs and improving the clarity of the code, would the time saved exceed the time lost? My anecdotal evidence is that it is a net benefit. It has rescued the Java world from the perils of type-casting, and I do remember getting many
ClassCastExceptionsin the past. Nowadays they are rare, and I don't spend excessive time on the complexities.