我如何在运行时得到通配符上界的类型



假设我要保存一个特定类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。也可能不是,因为调用者可能是错的。

所以我的问题是:我如何测试/验证objT的子类,这是一个通配符上界(所以我可以安全地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>,这将生成未检查强制转换警告。然而,因为你现在的objT,我认为类型安全是保留的。

@SuppressWarnings("unchecked")
public void register(T obj) {
    Class<? extends T> klass = (Class<? extends T>) obj.getClass();
    this.register(klass);
}

相关内容

  • 没有找到相关文章