假设我要保存一个特定类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
的子类,这是一个通配符上界(所以我可以安全地cast)?(我怀疑-或者也许,希望-答案涉及Guava的TypeToken
,这就是我添加Guava标签的原因,但我将接受任何答案,谢谢!)
您不应该能够注册任何类型的任何对象,这就是Object
类型在register
方法上的含义。
我将该参数的类型更改为T
。然后,您可以保证obj.getClass()
将返回Class<? extends T>
。编译器不会完全同意这一点,因为getClass()
的Javadocs状态:
实际结果类型为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);
}