Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to get the Generic Type Parameter?

Simply:

public static class MyClass<T> {
    // i don't want to keep an instance of T, if it is not necessary.
    // and it is not nice, not neat.

    // Or, let's say, the member are in the form of :
    ArrayList<T> mArrayList = new ArrayList<T>();
    // the problem of getting the generic type parameter is still present.
}

@Test
public final void test() {
    MyClass<Integer> myObject = new MyClass<Integer>();
    getParamType( myObject );
}

private static final <T> void getParamType(final MyClass<T> _myObject) {
    System.out.println(_myObject.getClass().getTypeParameters()[0]);    // T
    System.out.println(((T) new Object()).getClass());                  // class java.lang.Object
}

How to let the code print class java.lang.Integer?

i know quite a few of stackoverflow threads are asking (and answering) about this. Yet they couldn't solve this question.

  • i don't know why some need to call getGenericSuperclass() - as there is no inheritance involved in this simple case.
  • And i can't cast it to ParameterizedType as well.

.

System.out.println((ParameterizedType) _myObject.getClass());
// Compile Error: Cannot cast from Class<capture#11-of ? extends TreeTest2.MyClass> to ParameterizedType

System.out.println((ParameterizedType) _myObject.getClass().getGenericSuperclass());
// Runtime Exception: java.lang.ClassCastException

Based on @Thomas's guide, i have found a work-around way to get class java.lang.Integer.

First, we create an anonymous (it need to be anonymous) sub-class of MyClass<T> in the testing code. (Which is weird. Why it only support sub-classes?)

@Test
public final void test() {
    MyClass<Integer> myObject = new MyClass<Integer>() {};  // Anonymous sub-class
    getParamType( myObject );
}

Then we can use the getGenericSuperclass() method to get a Type then cast it to ParameterizedType and afterwards uses getActualTypeArguments():

private static final <T> void getParamType(final MyClass<T> _myObject) {
    System.out.println( ((ParameterizedType) _myObject.getClass().getGenericSuperclass()).getActualTypeArguments()[0] );
}

It perfectly prints class java.lang.Integer.

This is not-so-good because the testing codes should simulate the actual situation, where users most likely won't keep creating meaningless sub-classes.

This approach is based on the idea of the TypeReference class. But i don't really know how to use it. I have tried class MyClass<T> extends TypeReference<T>. But i still have to create sub-class of MyClass<T> to have TypeReference.getType() prints class java.lang.Integer.

Please help, and thanks for any inputs, as the best approach is not here yet.


A further question based on the above workaround: Why only anonymous sub-class works?

public static class SubMyClass<T> extends MyClass<T>{}

@Test
public final void test() {
    MyClass<Integer> myObject = new MyClass<Integer>() {};  // Anonymous sub-class
    getParamType( myObject );               // class java.lang.Integer

    MyClass<Integer> mySubObject = new SubMyClass<Integer>();   // named sub-class
    getParamType( mySubObject );            // T
}

(MyClass and getParamType() unchanged.)

like image 284
midnite Avatar asked Apr 24 '26 17:04

midnite


2 Answers

This is sort of difficult, because Java deliberately can't do that ("type erasure").

The work-around is called super type tokens. There are also some threads on SO about that (like this one or that one).

like image 72
barfuin Avatar answered Apr 26 '26 06:04

barfuin


When you have a question like this, you should ask yourself, how would you do it without Generics? Because any Generics program can be converted into an equivalent program without Generics. (This conversion is called type erasure.) So if you cannot do it without Generics, you cannot do it with Generics either.

Your program without Generics looks like this:

public static class MyClass {
    ArrayList mArrayList = new ArrayList();
}

@Test
public final void test() {
    MyClass myObject = new MyClass();
    Integer result = getParamType( myObject ); // how would you implement getParamType()?
}
like image 44
newacct Avatar answered Apr 26 '26 07:04

newacct



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!