我正在尝试获取类或接口实现的泛型类型。我知道这有一些风险和怪癖,但我想了解什么是可能的。
这是我的示例代码:
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;
}
}
这个输出是:
----------------------------------------------
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
因此,我的目标是让target
变量的值为Integer.class
。对于匿名类(#1)和显式类型的实现(#3),我能够按预期找到目标。为什么它在这些实例中工作而不是在#2(BaseImpl实例)的情况下?还有另一种方法来实现这一目标吗? (我知道通过实现类的构造函数传递目标Class
的常见解决方法,但我有兴趣动态地执行此操作)
我咨询了以下来源:
提前多多感谢,
阿贝尔
答案 0 :(得分:1)
来自http://tutorials.jenkov.com/java-reflection/generics.html(Bolds是我的)
使用Java Generics通常属于两种不同之一 情况强>:
将类/接口声明为可参数化。用一个 可参数化的类。当你编写类或接口时,你可以 指定它应该是可参数化的。就是这种情况 java.util.List接口。而不是创建一个Object列表 参数化java.util.List以创建一个表示String的列表。
运行时检查可参数化类型本身,如 java.util.List,无法知道已经是什么类型 参数化为。这是有道理的,因为类型可以参数化 在同一个应用程序中的各种类型。 但是,当你检查 您声明使用参数化类型的方法或字段 可以在运行时看到参数化参数化类型的类型 至即可。简而言之:
您无法在类型本身上看到它被参数化为a的类型 运行时,但您可以在使用它的字段和方法中看到它 参数即可。换句话说,它的具体参数化。
特定情况在页面上解释
答案 1 :(得分:0)
在案例1和案例3中,类型是类Main$1
和Main$TypedImpl
的反射数据的一部分,因此您可以访问它。
在案例2中,您只有实例数据,由于类型擦除不包含任何类型信息。因此,您无法在此处访问通用类型。
进一步解释:
在运行时,系统无法在BaseImpl<Integer> i;
和BaseImpl<String> s;
之间进行分析,即由于类型删除变量i
和s
属于BaseImpl
类型。
相比之下,TypedImpl t;
已知类型为TypedImpl
并使用反射,您可以提取extends
或implements
语句中提供的泛型类型。
旁注,因为您正在尝试了解可能的内容:
如果您将BaseImpl
定义为BaseImpl<T extends Number> implements MyInterface<T>
,则可以从类T
的反射数据中提取BaseImpl
的上限,即您{&lt; 1}}。 d能够知道T
必须是Number
或子类型(或接口情况下的实现)。