How can call public
using MyClass
as clazz where I can not instantiate or extend MyClas
How to do
MyClass<String>.class
in Java?
Generics in Java use type erasure; the type of the parametrized argument is enforced during compilation, but it is lost after compilation. The resulting byte code for an instance of a generic class does not contain any run-time meta-data on its arguments whatsoever.
As it is now, it is just not possible, a major language design blunder IMO.
T
corresponds to List
, so any reference to String
as the generic paramter of List
is irrelevant.
Use List.class
. Because of type erasure type parameters to Java classes are entirely a compile-time construct - even if List<String>.class
was valid syntax, it would be the exact same class as List<Date>.class
, etc. Since reflection is by nature a runtime thing, it doesn't deal well with type parameters (as implemented in Java).
If you want to use the Class object to (for example) instantiate a new List instance, you can cast the result of that operation to have the appropriate type parameter.
List<String> list = (List<String>)(ArrayList.class.newInstance());
I've seen similar questions asked several times, for example Acquiring generic class type
There are legitimate reasons to construct static generic types. In op' case, he would probably like to
MyClass<String> result = doit(MyClass<String>.class);
Without language syntax support, casting is the correct way to go. If this is needed quite often, the casting should be put in a method, as
public class MyClass<T>
{
@SuppressWarnings("unchecked")
// may need a better method name
static public <T2> Class<MyClass<T2>> of(Class<T2> tClass)
{
return (Class<MyClass<T2>>)(Class<?>)(MyClass.class);
}
}
MyClass<String> result = doit(MyClass.of(String.class)); // no warning
We can supress the warning on that method alone, after making sure the cast is safe. Any call site will not see the warning.
This is all compile time casting game. At runtime all the type parameters are erased, and really only the naked class object is passed around. The of
method will most likely be optimized off, so to JVM the last line is nothing but
MyClass result = doit(MyClass.class)
There are also times when at runtime we need a complete MyClass<String>
type. A ParameterizedType
object needs to be obtained to represent MyClass<String>
.
When the two requirements are combined together, that is, we need a compile time expression regarding MyClass
and String
that will evaluate at runtime to a ParameterizedType
ParameterizedType type_MyClass_String = ???? MyClass ?? String ???
There is a technique involving an anonymous subclass of MyClass<String>
ParameterizedType type_MyClass_String = superTypeOf( new MyClass<String>(){} );
which I find quite disturbing.
Since after your update your question does not appear to be an exact duplicate:
You would need to call getClass()
on an instance of MyClass
. Better have a dummy static final instance somewhere:
public static final MyClass INSTANCE = new MyClass();
...
return (Class<MyClass<String>>) instance.getClass();
See http://jackson.codehaus.org/1.7.0/javadoc/org/codehaus/jackson/type/TypeReference.html and the references that it references for a comprehensive discussion of the issues around generics.
the bottom line is that, if you really want to work with generic types in this way, you have to stop using Class
and start using Type
and its subclasses.
Contrary to your comment on another answer, you can write List<List<String>> obj = (List<List<String>>) doit(List.class);
, you just can't avoid a warning when you write it.