获取泛型类的泛型参数的类型名称

时间:2011-07-08 12:00:06

标签: java generics

在使用通用性时,我在java中遇到了一个小问题。我有一个班级A

public class A<T>

A的方法中,我需要获取T的类型名称。 有没有办法使用s找到字符串T

(如果我创建A<String> temp = new A<String>();,我希望能够在某一时刻获得java.lang.String - 我必须使用通用性,因为我的某个方法必须返回List<T>

这似乎很容易,但我不知道该怎么做。

7 个答案:

答案 0 :(得分:41)

由于类型删除,您通常无法执行此操作 - A<String>的实例不知道 T的类型。如果需要,一种方法是使用类型文字:

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

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

    // Use clazz in here
}

然后:

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

这很难看,但这就是类型擦除的作用:(

另一种方法是使用像Guice TypeLiteral这样的东西。这是有效的,因为用于指定超类的type参数不会被删除。所以你可以这样做:

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

a现在指的是A<String>子类,因此通过获取a.getClass().getSuperClass(),您最终可以返回String。但这太可怕了。

答案 1 :(得分:23)

您可以从子类中获取泛型的名称。看这个例子。 我们定义这样一个父类:

public class GetTypeParent<T> {

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

然后我们以这种方式定义它的子类:

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

您可以在main方法或任何实例方法中看到,我能够获取泛型类型的名称,在这种情况下,main将打印: java.lang.Integer

答案 2 :(得分:9)

简短回答:不可能。

稍微长一点的答案:编译代码后,类型参数将被丢弃。 因此,Java无法知道你在那里设置了什么。 但是,您可以将有问题的类传递给您的对象并对其进行操作:

public class A<T> {
  private final clazz;

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

答案 3 :(得分:5)

只要通过A:

的子类指定type参数,这当然是可能的
public class B extends A<String> {}

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

TypeResolver可通过TypeTools获得。

答案 4 :(得分:1)

Java中的泛型是通过擦除实现的,所以不,你将无法获得在运行时用于创建泛型集合的“类型”的名称。另外,为什么不检查元素以了解它属于哪种类型?

答案 5 :(得分:1)

如果你在一个子类中进行它,它的父类定义了泛型类型,那么这对我有用:

// get generic type class name
String name = ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0].toString();

// then when you've got the name, you can make the Class<T> object
Class.forName(name.replace("class ", ""))

在第一个片段中,我无法使用#getClass()代替#toString()的原因是我总是得到“Class”类,这对我来说毫无用处。

答案 6 :(得分:1)

通常情况下,Apache有一个使用TypeUtils的解决方案:

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

上述问题的一个简单例子:

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

免责声明:我没有先尝试构建此版本,但过去曾以类似的方式使用此实用程序。

相关问题