假设我正在保留某个类的子类注册表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
。它可能不会,因为调用者可能是错的。
所以我的问题是:我如何测试/验证obj
是T
的子类,它是一个通配符上限(所以我可以安全地转换)? (我怀疑 - 或许,希望 - 答案涉及番石榴TypeToken
,这就是为什么我添加了番石榴标签,但我会接受任何答案,谢谢!)
答案 0 :(得分:4)
您不应该注册任何类型的任何对象,这就是Object
方法中register
类型的含义。
我会将该参数的类型更改为T
。然后,您可以保证obj.getClass()
将返回Class<? extends T>
。编译器不太同意,因为Javadocs for getClass()
状态:
实际结果类型是Class,其中| X |是擦除调用getClass的表达式的静态类型。
对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);
}