Get type name for generic parameter of generic cla

2020-01-29 05:10发布

I have a small problem in java while using genericity. I have a class A :

public class A<T>

In a method of A, I need to get the type name of T. Is there a way to find the string s using T ?

(If I create A<String> temp = new A<String>();, I want to be able to get java.lang.String at one point - I have to use genericity because one of my methods will have to return a List<T>).

This seems quite easy but I do not see how to do it.

标签: java generics
7条回答
Bombasti
2楼-- · 2020-01-29 05:49

You can get the name of the generics from the subclass. See this example. We Define a parent class like this:

public class GetTypeParent<T> {

    protected String getGenericName()
    {
        return ((Class<T>) ((ParameterizedType) getClass()
                .getGenericSuperclass()).getActualTypeArguments()[0]).getTypeName();
    }
}

We then define its child class in this way:

public class GetTypeChild extends GetTypeParent<Integer> {
    public static void main(String[] args) {
        GetTypeChild getTypeChild = new GetTypeChild();
        System.out.println(getTypeChild.getGenericName());
    }
}

You can see that in the main method, or in any instance method, I am capable to get the name of the generics type, in this case the main will print: java.lang.Integer.

查看更多
够拽才男人
3楼-- · 2020-01-29 05:54

Short answer: Impossible.

Slightly longer answer: Once your code is compiled, the type parameters is discarded. Thus, Java cannot know what you set there. You could, however, pass the class in question to your object and operate on it:

public class A<T> {
  private final Class<T> clazz;

  A(Class<T> clazz){
     this.clazz = clazz;
  }
...
}
查看更多
劫难
4楼-- · 2020-01-29 05:56

As is normally the case, Apache has a solution for this one with TypeUtils:

https://commons.apache.org/proper/commons-lang/apidocs/org/apache/commons/lang3/reflect/TypeUtils.html

A quick example from the above question:

TypeUtils.getTypeArguments(temp.getClass(), A.class).get(A.class.getTypeParameters()[0])

Disclaimer: I did not attempt building this first, but have used this utility in a similar fashion in the past.

查看更多
老娘就宠你
5楼-- · 2020-01-29 06:03

Generics in Java are implemented by erasure, so no, you won't be able to get the name of the "type" which was used to create your generic collection at run-time. Also, why not just inspect the elements to know what type it belongs to?

查看更多
唯我独甜
6楼-- · 2020-01-29 06:04

You can't do this in general because of type erasure - an instance of A<String> doesn't know the type of T. If you need it, one way is to use a type literal:

public class A<T>
{
    private final Class<T> clazz;

    public A<T>(Class<T> clazz)
    {
        this.clazz = clazz;
    }

    // Use clazz in here
}

Then:

A<String> x = new A<String>(String.class);

It's ugly, but that's what type erasure does :(

An alternative is to use something like Guice's TypeLiteral. This works because the type argument used to specify a superclass isn't erased. So you can do:

A<String> a = new A<String>() {};

a now refers to a subclass of A<String>, so by getting a.getClass().getSuperClass() you can eventually get back to String. It's pretty horrible though.

查看更多
霸刀☆藐视天下
7楼-- · 2020-01-29 06:04

This certainly is possible so long as the type argument is specified via a subclass of A:

public class B extends A<String> {}

Class<?> typeArg = TypeResolver.resolveRawArgument(A.class, B.class);
assert typeArg == String.class;

TypeResolver is available via TypeTools.

查看更多
登录 后发表回答