Type erasure, reification and synthetic bridge methods: yuck. I'm stuck on the proverbial consultants' bench so I decided - after 4 years of non-Java development - to upgrade my Java certification to the latest version in just five days. I honestly thought I was going to make the deadline until I hit the section on generics. Now I'm a half-day behind and my head hurts! C# is way easier to grasp, and from the looks of things performs a whole bunch better too (except for the JITed type instance "explosion" if you really care).
Anyway, since Java 5, the Class class in package java.lang is a generic class whose type parameter denotes the type that the Class object represents. Previously, compilers wouldn't let you compare an Integer and a String. Now (since Tiger) they won't even let you compare Integer.class and String.class! It stems back to the fact that (similar to C#) both GenericType<A> and GenericType<B> do not derive from each other, even though type B extends type A. There's a little bit of extra trickery in the Java though, because both GenericType<A> and GenericType<A> extend GenericType<?> (unlike C# where they derive from System.Object.) This means that you CAN compare a GenericType<capture of ? extends Object> with a GenericType<capture of ? extends String>! Madness.