Java 在运行时获取泛型类型:在某些情况下有效,但在其他情况下无效-为什么?

Java 在运行时获取泛型类型:在某些情况下有效,但在其他情况下无效-为什么?,java,generics,dynamic,Java,Generics,Dynamic,我正在尝试获取类或接口实现的泛型类型。我知道这有一些风险和怪癖,但我正在努力理解什么是可能的 下面是我的示例代码: import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; import java.util.Arrays; import java.util.LinkedList; public class Main { public interface MyInterface<T>

我正在尝试获取类或接口实现的泛型类型。我知道这有一些风险和怪癖,但我正在努力理解什么是可能的

下面是我的示例代码:

import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.Arrays;
import java.util.LinkedList;

public class Main {

    public interface MyInterface<T> {
    }

    public static class BaseImpl<T> implements MyInterface<T> {
    }

    public static class TypedImpl extends BaseImpl<Integer> {
    }

    public static void main(String[] args) throws Exception {
        LinkedList<MyInterface<Integer>> instances = new LinkedList<>();

        // 1. anonymous class from interface
        instances.add(new MyInterface<Integer>() {
        });

        // 2. class extending interface
        instances.add(new BaseImpl<Integer>());

        // 3. class with pre-defined generic type
        instances.add(new TypedImpl());

        for (MyInterface<Integer> instance : instances) {
            System.out.println("----------------------------------------------");

            Class clazz = instance.getClass();
            Type genericSuper = clazz.getGenericSuperclass();
            Type[] genericInterfaces = clazz.getGenericInterfaces();
            Class target = null;

            System.out.println("class: " + clazz.getName());
            System.out.println("generic super: " + genericSuper);
            System.out.println("generic interfaces: " + Arrays.asList(genericInterfaces));

            // attempt to 'extract' generic type
            if (genericSuper instanceof ParameterizedType) {
                target = getGeneric((ParameterizedType) genericSuper);
            } else if (genericInterfaces.length > 0) {
                for (Type genericInterface : genericInterfaces) {
                    if (genericInterface instanceof ParameterizedType) {
                        target = getGeneric((ParameterizedType) genericInterface);

                        if (null != target) {
                            break;
                        }
                    }
                }
            }

            System.out.println("TARGET: " + target);
        }
    }

    // attempt to get type argument
    public static Class getGeneric(ParameterizedType type) {
        if (MyInterface.class.isAssignableFrom((Class) type.getRawType())) {
            Type typeArg = type.getActualTypeArguments()[0];

            try {
                return (Class) typeArg;
            } catch (ClassCastException e) {
                System.out.println("cast exception for '" + typeArg + "'");
            }
        }

        return null;
    }

}
import java.lang.reflect.ParameterizedType;
导入java.lang.reflect.Type;
导入java.util.array;
导入java.util.LinkedList;
公共班机{
公共接口MyInterface{
}
公共静态类BaseImpl实现MyInterface{
}
公共静态类TypedImpl扩展了BaseImpl{
}
公共静态void main(字符串[]args)引发异常{
LinkedList实例=新建LinkedList();
//1.来自接口的匿名类
添加(新的MyInterface(){
});
//2.类扩展接口
add(newbaseimpl());
//3.具有预定义泛型类型的类
add(newtypedimpl());
对于(MyInterface实例:实例){
System.out.println(“-------------------------------------------------------------”;
Class clazz=instance.getClass();
键入genericSuper=clazz.getGenericSuperclass();
类型[]genericInterfaces=clazz.getGenericInterfaces();
类目标=null;
System.out.println(“类:+clazz.getName());
System.out.println(“通用超级:“+genericSuper”);
System.out.println(“通用接口:“+Arrays.asList(GenericInterface));
//尝试“提取”泛型类型
if(参数化类型的genericSuper实例){
target=getGeneric((ParameteredType)genericSuper);
}else if(genericInterfaces.length>0){
for(类型genericInterface:genericInterface){
if(参数化类型的通用接口实例){
target=getGeneric((ParameteredType)genericInterface);
如果(空!=目标){
打破
}
}
}
}
System.out.println(“目标:+TARGET”);
}
}
//尝试获取类型参数
公共静态类getGeneric(ParameterizedType类型){
if(MyInterface.class.isAssignableFrom((class)type.getRawType())){
Type typeArg=Type.getActualTypeArguments()[0];
试一试{
返回(类)类型参数;
}catch(ClassCastException e){
System.out.println(“针对''+typeArg+''的强制转换异常”);
}
}
返回null;
}
}
其输出为:

----------------------------------------------
class: Main$1
generic super: class java.lang.Object
generic interfaces: [Main.Main$MyInterface<java.lang.Integer>]
TARGET: class java.lang.Integer
----------------------------------------------
class: Main$BaseImpl
generic super: class java.lang.Object
generic interfaces: [Main.Main$MyInterface<T>]
cast exception for 'T'
TARGET: null
----------------------------------------------
class: Main$TypedImpl
generic super: Main.Main$BaseImpl<java.lang.Integer>
generic interfaces: []
TARGET: class java.lang.Integer
----------------------------------------------
类别:主要$1
泛型超级类:java.lang.Object
通用接口:[Main.Main$MyInterface]
目标:类java.lang.Integer
----------------------------------------------
类别:Main$BaseImpl
泛型超级类:java.lang.Object
通用接口:[Main.Main$MyInterface]
“T”的强制转换例外
目标:空
----------------------------------------------
类别:Main$TypedImpl
通用超级:Main.Main$BaseImpl
通用接口:[]
目标:类java.lang.Integer
因此,我的目标是使
target
变量的值为
Integer.class
。对于匿名类(#1)和显式类型化实现(#3),我能够按预期找到目标。为什么它在这些实例中有效,而在#2(BaseImpl实例)中无效?有没有其他方法可以做到这一点?(我知道通过实现类的构造函数传递目标
的常见解决方法,但是我对动态地这样做感兴趣)

我曾征询下列人士的意见:

提前多谢了


Abel

在案例1和案例3中,类型是类
Main$1
Main$TypedImpl
上反射数据的一部分,因此您可以访问它

在案例2中,由于类型擦除,只有实例数据不包含任何类型信息。因此,您无法在此处访问泛型类型

进一步解释:

在运行时,系统无法区分
BaseImpl iBaseImpl s,即由于类型擦除,两个变量
i
s
都属于
BaseImpl
类型

相比之下,
TypedImpl t的类型为
TypedImpl
,使用反射可以提取
extends
implements
语句中提供的泛型类型

旁注,由于您正试图了解什么是可能的:

如果将
BaseImpl
定义为
BaseImpl实现MyInterface
,则可以从类
BaseImpl
上的反射数据中提取
T
的上限,即,您可以知道
T
必须是
Number
或子类型(或接口的实现)。

(黑体字是我的)

使用Java泛型通常分为两种不同的方法之一 情况:

将类/接口声明为可参数化的 可参数化类。当您编写类或接口时,您可以 指定它应该是可参数化的 您可以创建对象列表,而不是创建对象列表 参数化java.util.List以创建所述字符串的列表

运行时检查可参数化类型本身时,如 如果是java.util.List,则无法知道类型是什么 参数化为。这很有意义,因为类型可以参数化 适用于同一应用程序中的所有类型。但是 声明使用参数化类型的方法或字段 可以在运行时看到什么类型的