16

How can call public <T> T doit(Class<T> clazz); using MyClass<String>.class as clazz where I can not instantiate or extend MyClass.

EDIT: 'David Winslow' and 'bmargulies' responses are correct (MyClass<String>) doit(MyClass.class); works for the original question BUT surprisingly when the method returns say MyClass<T> instead of T casting will not compile any more.

Edit: I have replaced List with MyClass and added the condition to my original question.

Ali Shakiba
  • 20,549
  • 18
  • 61
  • 88
  • possible duplicate of [How to create expressions of type Class>](http://stackoverflow.com/questions/2012306/how-to-create-expressions-of-type-classlist) – Bozho Mar 05 '11 at 22:29
  • @Bozho See update. I had simplified my real situation. – Ali Shakiba Mar 05 '11 at 22:36

6 Answers6

14

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());
David Winslow
  • 8,472
  • 1
  • 31
  • 27
  • "can't do this" is not a good way to describe technical issues. Does the code compile? Is there an error at runtime? Does someone come and take away your keyboard every time you try to compile? – David Winslow Mar 05 '11 at 23:05
  • yes I was wrong, I removed my comment. I had another error too, I'm still working. – Ali Shakiba Mar 05 '11 at 23:10
7

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.

Community
  • 1
  • 1
irreputable
  • 44,725
  • 9
  • 65
  • 93
2

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.

bmargulies
  • 97,814
  • 39
  • 186
  • 310
1

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();
Community
  • 1
  • 1
Bozho
  • 588,226
  • 146
  • 1,060
  • 1,140
0

T corresponds to List, so any reference to String as the generic paramter of List is irrelevant.

Jeremy
  • 22,188
  • 4
  • 68
  • 81
-1

How to do MyClass<String>.class in Java?

You can't.

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.

luis.espinal
  • 10,331
  • 6
  • 39
  • 55
  • But did you know about ParameterizedType http://download.oracle.com/javase/1.5.0/docs/api/java/lang/reflect/ParameterizedType.html – Ali Shakiba Mar 06 '11 at 00:34
  • ParameterizedType is a kludge IMO, and it is not the same (syntactically or semantically) as evaluating `MyClass.class` just as one would with, say, `X.class` for an arbitrary class or interface. By default, one can call `X.class` w/o worrying about runtime or checked exceptions. OTH, ParameterizedType can only be made to work with classes extending generic classes (.ie. `class StringList extends ArrayList`). Then, the JVM can keep track of `inherited` generic parameter types, but won't otherwise. Plus, you have to deal with potential exceptions when using it. Not the same. – luis.espinal Mar 06 '11 at 04:39