Unfortunately, generics in Java (and the up-coming C# 2.0) are a
leaky abstraction. That is, when they work, they work well. But if something goes wrong, you need to understand how they are implemented to be able to grok the problem.
For example, in both C# 2.0 and Java 1.5, the following is illegal:
class MyGeneric<T>{ public void Method(object o) { if (o is T) // error { T tmp = new T(); // error } } public void Blah(T var) { var.OtherMethod(); // error }}
These things may seem valid to someone familiar with C++, but are not allowed in either C# or Java.
At least C# provides some performance benefits when using generics. Because they're part of the byte code, you don't have those runtime casts anymore. It also includes further benefits when using value types, because it removes the implicit boxing required now when you store a value type as an object.
The other problem is that it's still possible in Java to get a CastException -
even when your code contains no casts, because at the bytecode allows you to add objects of a different type to your generic collection and when you get an object out of it, java adds the implicit cast for you.
Anyway, that's enough of a rant from me :)