List list = new ArrayList();
String x = (String) list.get(0);
List<String> list = new ArrayList<String>();
String x = list.get(0);
... but the List<T> interface itself still advertises itself as being generic.
@Rogerio: As I replied to your comment, I believe you're getting confused between being able to get the type of a variable and being able to get the type of an object. The object itself doesn't know its type argument, even though the field does.
@Rogerio: How do you know where the object has come from though? If you have a parameter of type List<? extends InputStream> how can you know what type it was when it was created? Even if you can find out the type of the field the reference has been stored in, why should you have to? Why should you be able to get all the rest of the information about the object at execution time, but not its generic type arguments? You seem to be trying to make type erasure out to be this tiny thing which doesn't affect developers really - whereas I find it to be a very significant problem in some cases.
At execution time there's no way of finding out that T=String for the list object - that information is gone.
But type erasure IS a tiny thing which doesn't really affect developers! Of course, I can't speak for others, but in MY experience it never was a big deal. I actually take advantage of runtime type information in the design of my Java mocking API (JMockit); ironically, .NET mocking APIs seem to take less advantage of the generic type system available in C#.
EDIT: Just to clarify, the compiler does retain the information about the variable being a List<String> - but you still can't find out that T=String for the list object itself.
No, even in the use of a generic type there may be metadata available at runtime. A local variable is not accessible through Reflection, but for a method parameter declared as "List<String> l", there will be type metadata at runtime, available through the Reflection API. Yep, "type erasure" is not as simple as many people think...
Of course, just looking at the object itself you can't know that it's a List<String>. But objects don't just appear from nowhere. They are created locally, passed in as a method invocation argument, returned as the return value from a method call, or read from a field of some object... In all these cases you CAN know at runtime what the generic type is, either implicitly or by using the Java Reflection API.
Type erasure applies to the use of generics. There's definitely metadata in the class file to say whether or not a method/type is generic, and what the constraints are etc. But when generics are used, they're converted into compile-time checks and execution-time casts. So this code: