java有可能获得接口的泛型类型吗?
鉴于接口:
interface GenericInterface<T> {
Class<T> getGenericType();
}
以及以下实施“框架”:
class GenericInterfaceImpl<T> implements GenericInterface<T> { /* impl */ }
class TypedInterfaceImpl implements GenericInterface<String> { /* impl */ }
以传递以下断言的方式定义getGenericType
的实现:
assertEquals(new GenericInterfaceImpl<String>().getGenericType(), String.class, "Type should resolve to String.class");
assertEquals(new TypedInterfaceImpl().getGenericType(), String.class, "Type should resolve to String.class");
我非常清楚有一个很好的实现可以在TypedInterfaceImpl
“场景”中解决这个问题。以下代码传递第二种情况的断言:
@Override
@SuppressWarnings("unchecked")
Class<T> getGenericType() {
Type t = this.getClass().getGenericInterfaces()[0];
ParameterizedType pt = (ParameterizedType) t;
return (Class<T>) pt.getActualTypeArguments()[0];
}
但是,如果我处理这个问题的GenericInterfaceImpl
版本,我找不到一种方法来获得相同的结果。当将上述实现与GenericInterfaceImpl
一起使用时,“类型参数”解析为sun.reflect.generics.reflectiveObjects.TypeVariableImpl
,而不是像处理TypedInterfaceImpl
时那样的java.lang.String
用于getGenericInterfaces
的Javadocs明确声明,如果没有在源代码中定义类型参数,它将不会解析类型参数(参考:https://docs.oracle.com/javase/8/docs/api/java/lang/Class.html#getGenericInterfaces--在我的特定情况下,我使用的是java11,但它是相同的),因此根据定义,我理解这个特定方法无法解决这个问题
有没有办法解决这个问题,或者这是Java语言的“核心限制”
# 1 楼答案
不可能
可能,但不是个好主意;它要求您使用“在实现此接口时,您必须为
T
选择一个具体的、非类型参数化的类型,否则一切都不正常”来记录接口,这是一个奇怪的警告坏主意;
<>
中的东西不一定是Class
-例如,它可能是List<String>
,它不能表示为类对象(只有List
是,有一个对象表示所有列表,无法有一个代表List<String>
的j.l.class实例)getGenericInterfaces
是一个反射工具,但它只反映类型的定义。给定class Foo<T> implements Thingie<T>
,getGenericInterfaces
只能在整个Foo
类上执行,然后返回一个表示Thingie<T>
的对象。给定new Foo<String>()
这样的实例,不可能派生字符串这是一个核心限制,所以,不,不是直接的
一个技巧是添加一个方法:
让实施者担心这个问题。这仍然是一个坏主意,例如,
Class
对象不能表示List<String>
,因此您已经有效地使Foo无法正确地表示任何您希望T
具有类型参数的对象退后一步。你到底想做什么?没有人醒来就走:我知道!我将构建一个接口,它可以报告它自己的类型参数,但是具体化了!你想建造什么?聊天应用?photoshop的插件系统
java.lang.Class
是一个非常糟糕的工厂,目的是在它上面调用.newInstance()
。因此,如果你打算这样做,就用工厂代替Anotehr解决方案,但您可能不想要这个,在您兴奋之前,它有很多限制,是一个称为超级类型令牌的概念;如果你必须知道的话,你可以在网上搜索