Java 如何在运行时获取泛型类型?

Java 如何在运行时获取泛型类型?,java,generics,reflection,Java,Generics,Reflection,这是我的代码: ExecuteImp扩展了AbstractExecutor,AbstractExecutor提取其实现者的相同执行逻辑(ExecuteImp是一种情况),当调用ExecuteImp的execute()方法时,它将在其超类型中调用该方法,但超类型(AbstractExecutor)应该知道另一个绑定到实现者的类(在本例中,它是用户类): import java.lang.reflect.InvocationTargetException; 导入java.util.ArrayList

这是我的代码: ExecuteImp扩展了AbstractExecutor,AbstractExecutor提取其实现者的相同执行逻辑(ExecuteImp是一种情况),当调用ExecuteImp的execute()方法时,它将在其超类型中调用该方法,但超类型(AbstractExecutor)应该知道另一个绑定到实现者的类(在本例中,它是用户类):

import java.lang.reflect.InvocationTargetException;
导入java.util.ArrayList;
抽象类抽象执行器{
public void execute()引发异常{
ArrayList=新建ArrayList();
//这里我想得到真正的“E”
Class cl=this.getClass().getTypeParameters()[0].getGenericDeclaration().getClass();
对象o=cl.getConstructor(String.class).newInstance(“门”);
增加((E)o);
System.out.println(格式(列表));
}
公共抽象字符串格式(ArrayList列表);
公共抽象字符串getType();
}
公共类ExecutorMP扩展了AbstractExecutor{
@凌驾
公共字符串getType(){
返回“用户”;
}
@凌驾
公共字符串格式(ArrayList列表){
StringBuffer sb=新的StringBuffer();
用于(用户u:列表){
sb.append(u.toString()+);
}
使某人返回字符串();
}
公共静态void main(字符串[]args)引发异常{
新的ExectorImp().execute();
}
}
类用户{
字符串名;
公共用户(字符串名称){
this.name=名称;
}
}

那么,我的代码有什么问题吗?

我认为您应该使用
getActualTypeParameters
;as
getTypeParameters
不是指在当前实例化中放置了什么来代替
E
,而是指
E
本身(描述它是如何定义的,等等)

要获取
参数化类型
,应首先使用
getGenericSuperclass

更新:但只有当当前对象派生自已实例化泛型参数的泛型类时,上述操作才有效,如:

class StringList extends ArrayList<String> {
    public Type whatsMyGenericType() {
        return ((ParameterizedType)getGenericSuperClass()).getActualTypeParameters()[0];
    }
}
class StringList扩展了ArrayList{
公共类型whatsMyGenericType(){
返回((ParameteredType)getGenericSuperClass()).getActualTypeParameters()[0];
}
}

应该返回
String.class

我认为您无法在运行时获得泛型类型。泛型类型是在编译时应用的限制。我记得在运行时,泛型集合和没有泛型类型的集合之间没有区别。

解决此问题的通常方法是稍微更改代码。在接受
class
参数的基类上定义构造函数。将此参数指定给内部字段

在子类上定义不带参数的构造函数,并从那里调用
super(User.class)


通过这种方式,您将了解参数类,而不会给子类的客户端带来太多负担。

这里有一些混淆。由于类型擦除,您无法从运行时参数化类型获取类型信息,如:

Class<E> cls = E.getClass(); // Error.
E e = new E(); // Error.

更新:关于是否建议这样做,尽管这样做会起作用,但只要类声明中发生微小更改,这对运行时问题很敏感。作为开发人员,您应该正确地记录它。作为一种完全不同的选择,您可以利用多态性

abstract class AbstractExecutor<E> {

    public void execute() throws Exception {
        List<E> list = new ArrayList<E>();
        E e = create("Gate");
        list.add(e);
        System.out.println(format(list));
    }

    public abstract E create(String name);

    // ...
}

确切地说:getGenericSuperclass()仅在类不是泛型类时才会为您提供有意义的结果,因此:new LinkedList().getClass().getGenericSuperclass()对您来说不够,但是:new LinkedList(){}.getClass().getGenericSuperclass()可以-注意到区别了吗?通过添加{}我创建了LinkedList的子类。@iirekm true,那么我想对象无法检测它是如何被反射声明的,但是它可以“从外部”完成(例如,使用
Field.getGenericType()
)。不完全正确:通过“fortran”阅读解决方案以及我对它的注释。他,我也曾经想过。。。擦除意味着在编译时,您可以忽略通用限制,因为运行两个实例的字节码是相同的,但有关如何声明实例的信息会保留下来。非常感谢,也感谢本页中的所有人。BalusC的答案是我想要的。但是我想知道我的代码是否被推荐?以下是我的应用程序上下文:也许这个答案可以帮助解决您的问题。
abstract class AbstractExecutor<E> {

    public void execute() throws Exception {
        List<E> list = new ArrayList<E>();
        Class<E> cls = (Class<E>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0];
        E e = cls.getConstructor(String.class).newInstance("Gate");
        list.add(e);
        System.out.println(format(list));
    }

    // ...
}
abstract class AbstractExecutor<E> {

    public void execute() throws Exception {
        List<E> list = new ArrayList<E>();
        E e = create("Gate");
        list.add(e);
        System.out.println(format(list));
    }

    public abstract E create(String name);

    // ...
}
class UserExecutor extends AbstractExecutor<User> {

    @Override
    public User create(String name) {
        return new User(name);
    }

    // ...
}