不幸的是,由于类型擦除和反射API的限制相结合,您要尝试的工作非常复杂。
这是真的,你可以使用的组合获得了超类的通用参数
Class.getGenericSuperclass和
ParameterizedType.getActualTypeArguments。这是例如Guava
TypeToken类用于捕获通用类型参数的机制。但是,您要的是接口的通用类型参数,该参数可能已在继承链的任何位置实现了,尽管接口本身可以在自由解析或声明新类型参数的同时彼此继承。
为了演示,请采用以下方法:
static void inspect(Object o) { Type type = o.getClass(); while (type != null) { System.out.print(type + " implements"); Class<?> rawType = (type instanceof ParameterizedType) ? (Class<?>)((ParameterizedType)type).getRawType() : (Class<?>)type; Type[] interfaceTypes = rawType.getGenericInterfaces(); if (interfaceTypes.length > 0) { System.out.println(":"); for (Type interfaceType : interfaceTypes) { if (interfaceType instanceof ParameterizedType) { ParameterizedType parameterizedType = (ParameterizedType)interfaceType; System.out.print(" " + parameterizedType.getRawType() + " with type args: "); Type[] actualTypeArgs = parameterizedType.getActualTypeArguments(); System.out.println(Arrays.toString(actualTypeArgs)); } else { System.out.println(" " + interfaceType); } } } else { System.out.println(" nothing"); } type = rawType.getGenericSuperclass(); }}这将反映一个对象,并爬升其继承链以报告其已实现的接口及其通用参数(如果适用)。
让我们在您列出的第一种情况下尝试一下:
inspect(new ArrayList<SomeObject>());
打印:
class java.util.ArrayList implements: interface java.util.List with type args: [E] interface java.util.RandomAccess interface java.lang.Cloneable interface java.io.Serializablejava.util.AbstractList<E> implements: interface java.util.List with type args: [E]java.util.AbstractCollection<E> implements: interface java.util.Collection with type args: [E]class java.lang.Object implements nothing
您可以看到type参数
E尚未解析。给定类型擦除,这是完全可以理解的-在运行时对应于的字节码指令
newArrayList<SomeObject>()没有概念
SomeObject。
匿名类的情况不同:
inspect(new Iterable<SomeObject>() { @Override public Iterator<SomeObject> iterator() { throw new UnsupportedOperationException(); }});印刷品:
class sandbox.Main$1 implements: interface java.lang.Iterable with type args: [class sandbox.SomeObject]class java.lang.Object implements nothing
在这里,由于匿名类通过实现解析了类型参数,因此在运行时可以使用类型参数
Iterable<SomeObject>。
ListOfSomeObjects它的任何子类都可以出于相同的原因工作。
好的,只要继承链中的某个类
E一路解析了类型参数,我们就可以进行匹配吗?不幸的是,没有,至少不是以上方法:
inspect(new ArrayList<SomeObject>() { });打印:
class sandbox.Main$1 implements nothingjava.util.ArrayList<sandbox.SomeObject> implements: interface java.util.List with type args: [E] interface java.util.RandomAccess interface java.lang.Cloneable interface java.io.Serializablejava.util.AbstractList<E> implements: interface java.util.List with type args: [E]java.util.AbstractCollection<E> implements: interface java.util.Collection with type args: [E]class java.lang.Object implements nothing
您可以看到的type参数
ArrayList已知为
SomeObject,但这就是它的停止位置。类型参数之间没有连接关系。原因是这段代码:
Class<?> rawType = (type instanceof ParameterizedType) ? (Class<?>)((ParameterizedType)type).getRawType() : (Class<?>)type;Type[] interfaceTypes = rawType.getGenericInterfaces();
getGenericInterfaces是获取接口的类型参数信息的唯一方法,但是该方法是由
Class而不是声明的
Type。只要该方法有一个
ParameterizedType实例,该实例拥有表示其子类的通用性的状态,就会被强制调用
getRawType,它返回
Class没有类型实参信息的单例。这是一个问题22,导致只能获得使用具体类型实参实现的接口的类型实参。
我不知道任何将类型实参与它们解析的参数匹配的反射API方法。从理论上讲,可以编写反射性代码,使其爬上继承链,找到实现的类
Iterable(或子接口),然后向下爬回直到与相应的类型参数匹配。不幸的是,我不认为这将如何实现。类可以随意使用任何名称和所需的顺序声明类型参数,因此可以不进行基于名称或位置的幼稚匹配。也许其他人可以提供解决方案。



