12

There are other related questions e.g. 6624113, 3403909, 4516891 but my question is simpler and more specific.

I want to know at runtime what type my class was parameterized with - I want a Class object of the type of the type parameter. Because of type erasure, the expression T.class doesn't work, and there is no function like typeof(T) in C# to get it.

However, there is some "uber-reflection" available via ParameterizedType and related classes, which gets me almost all of the way there.

import java.lang.reflect.ParameterizedType;

public class MyClass<T> {
    public static void main( String[] args ) {
        new MyClass<Integer>().printTypeParam();
    }

    public void printTypeParam() {
        class DummyT extends MyClass<T> {}
        class DummyString extends MyClass<String> {}

        ParameterizedType ptT =
            ((ParameterizedType) DummyT.class.getGenericSuperclass() );

        ParameterizedType ptString =
            ((ParameterizedType) DummyString.class.getGenericSuperclass() );

        System.out.println( "DummyT: " + ptT + " " + ptT.getActualTypeArguments()[0] );
        System.out.println( "DummyString: " + ptString + " " + ptString.getActualTypeArguments()[0] );

    }
}

When I run the above I see this output:

DummyT: MyClass<T> T
DummyString: MyClass<java.lang.String> class java.lang.String

As you can see, this works for when the type arguments are known at compile-time at the line of code containing the call to getGenericSuperClass, but where that call is itself dealing with generics it simply prints the name of the type parameter.

Is there any way I can get the first line to print java.lang.Integer instead of T?

Community
  • 1
  • 1
Andy Balaam
  • 6,423
  • 6
  • 34
  • 37

1 Answers1

4

You can't, plain and simple. Integer is not reified, it is completely erased. If you don't believe me, compile the file once with Integer and once with Long. The two binary class files will be absolutely identical.

Type erasure is a harsh reality that you won't be able to get around. I suggest you rethink why you need it instead of going down the path of introducing hacks to try to avoid it.

Useful AngelikaLanger Generics FAQ topics:

Mark Peters
  • 80,126
  • 17
  • 159
  • 190
  • 2
    I actually did what you suggested, and you will be unsurprised to hear you are right: 2 files are created: MyClass$1DummyString.class MyClass$1DummyT.class MyClass.class and they are binary-identical if I change the type on line 5 to Long instead of Integer. – Andy Balaam Nov 04 '11 at 17:00
  • I am happily using the workaround/pattern of passing a class instance to the constructor - I was just curious on whether the less-verbose solution was possible. – Andy Balaam Nov 04 '11 at 17:01