如何在运行时获取通配符上限的类型?
How can I get at runtime the type of a wildcard upper bound?
假设我正在保留某个 class、T
:
的子classes 的注册表
public class ClassRegistry<T> {
Set<Class<? extends T>> klasses;
...
public void register(Class<? extends T> klass) {
klasses.add(klass);
}
您通过 registry.register(this.getClass())
这样的电话注册自己。我想通过 ClassRegistry<T>
上的方法简化此操作,您只需传递自己 this
,例如 registry.register(this)
:
public void register(Object obj) {
Class<?> klass = obj.getClass();
this.register(klass);
}
糟糕,这是错误的,因为它会调用自身(将重载与参数类型 Object
匹配,当然不是 Class<? extends T>
)。所以,改为:
public void register(Object obj) {
Class<? extends T> klass = obj.getClass();
this.register(klass);
}
现在当然无法编译,因为编译器不知道您的 obj
实际上是某种类型 ? extends T
。它可能不会,因为调用者可能是错误的。
所以我的问题是:我如何 test/validate obj
是 T
的子 class,它是通配符上限(这样我就可以安全地投)? (我怀疑 - 或者也许希望 - 答案涉及 Guava 的 TypeToken
,这就是我添加 Guava 标签的原因,但我会接受任何答案,谢谢!)
您不应该能够注册任何类型的任何对象,这就是类型 Object
在您的 register
方法中的含义。
我会将该参数的类型更改为 T
。那么,你可以保证obj.getClass()
会return一个Class<? extends T>
。编译器不会完全同意这一点,因为 Javadocs for getClass()
状态:
The actual result type is Class where |X| is the erasure of the static type of the expression on which getClass is called.
调用getClass()
的结果不是Class<? extends T>
,而是Class<? extends Object>
(T
的擦除)。您可以将其转换为 Class<? extends T>
,这将生成一个未经检查的转换警告。但是,因为你现在 obj
是一个 T
,我认为类型安全是保留的。
@SuppressWarnings("unchecked")
public void register(T obj) {
Class<? extends T> klass = (Class<? extends T>) obj.getClass();
this.register(klass);
}
假设我正在保留某个 class、T
:
public class ClassRegistry<T> {
Set<Class<? extends T>> klasses;
...
public void register(Class<? extends T> klass) {
klasses.add(klass);
}
您通过 registry.register(this.getClass())
这样的电话注册自己。我想通过 ClassRegistry<T>
上的方法简化此操作,您只需传递自己 this
,例如 registry.register(this)
:
public void register(Object obj) {
Class<?> klass = obj.getClass();
this.register(klass);
}
糟糕,这是错误的,因为它会调用自身(将重载与参数类型 Object
匹配,当然不是 Class<? extends T>
)。所以,改为:
public void register(Object obj) {
Class<? extends T> klass = obj.getClass();
this.register(klass);
}
现在当然无法编译,因为编译器不知道您的 obj
实际上是某种类型 ? extends T
。它可能不会,因为调用者可能是错误的。
所以我的问题是:我如何 test/validate obj
是 T
的子 class,它是通配符上限(这样我就可以安全地投)? (我怀疑 - 或者也许希望 - 答案涉及 Guava 的 TypeToken
,这就是我添加 Guava 标签的原因,但我会接受任何答案,谢谢!)
您不应该能够注册任何类型的任何对象,这就是类型 Object
在您的 register
方法中的含义。
我会将该参数的类型更改为 T
。那么,你可以保证obj.getClass()
会return一个Class<? extends T>
。编译器不会完全同意这一点,因为 Javadocs for getClass()
状态:
The actual result type is Class where |X| is the erasure of the static type of the expression on which getClass is called.
调用getClass()
的结果不是Class<? extends T>
,而是Class<? extends Object>
(T
的擦除)。您可以将其转换为 Class<? extends T>
,这将生成一个未经检查的转换警告。但是,因为你现在 obj
是一个 T
,我认为类型安全是保留的。
@SuppressWarnings("unchecked")
public void register(T obj) {
Class<? extends T> klass = (Class<? extends T>) obj.getClass();
this.register(klass);
}