As previously mentioned, generics hurt my head. Sun's Java generics tutorial calls Collections.max() one of the subtlest examples of the use of generics.
public static <T extends Object & Comparable<? super T>> T max(Collection<? extends T> coll)
Subtle is one word for it. Anyway, to my walnut-sized brain, generics are confusing; maybe too confusing to be worth it. Was ClassCastException really a major problem for anybody?
Generics can be used in two places. Generic classes, like List<T>, and generic methods, like Collections.max().
As I learned in Programming Languages 505, return types are covariant while method parameters are contravariant (see the wikipedia entry). Generics, because they can be used to parameterize both return types and method parameters, are invariant. Keeping this in mind explains a lot. Thus, List<String> is not a subtype of List<Object>. This leads to a lot of confusion, particularly because Arrays in Java took the opposite choice. String is a subtype of Object. Aaarg!
Wildcards attempt to mitigate this problem, with extends and super.
List<? extends Flapdoodle> TreeSet(Comparator<? super E> c)
I pronounce List<?> as "list of WTF". You're really supposed to say it's an unbounded wildcard type. Seems about as annoying as @SuppressWarnings("unchecked").
Effective Java 2nd Ed., Generics
- Produce-extends, consumer-super
In other words, if a parameterized type represents a T producer, use <? extends T>; if it represents a T consumer, use <? super T>.
- Private helper method for wildcard capture
- Typesafe heterogeneous containers