java - 如何在运行时获取通配符上限的类型?

标签 java generics reflection guava type-erasure

假设我正在保留某个类的子类的注册表,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 的子类这是一个通配符上限(所以我可以安全地转换)? (我怀疑 - 或者也许希望 - 答案涉及 Guava 的 TypeToken ,这就是我添加 Guava 标签的原因,但我会接受任何答案,谢谢!)

最佳答案

你不应该能够注册任何类型的任何对象,这就是类型 Object意味着你的 register方法。

我会将该参数的类型更改为 T .然后,你可以保证 obj.getClass()将返回 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> ,这将生成未经检查的类型转换警告。但是,因为你现在objT ,我认为保留了类型安全。

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

关于java - 如何在运行时获取通配符上限的类型?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32277554/

相关文章:

java - AtomicLong 与 Long 性能

java - 我可以从 IntelliJ 12 中的搜索结果运行所有测试吗?

java - 从 Java 中的泛型类型推断泛型类型(编译时错误)

java - 将 java.lang.reflect.getMethod 与多态方法一起使用

c# - 通过 C# 中的反射获取 'basic' 数据类型而不是奇怪的可空数据类型

java - 可以使用带有用户名和密码的Java FileReader(或类似的东西)吗?

java - 包裹main方法的类的作用是什么?

c# - 通用对象的通用列表

java - 如何在基类中创建Java泛型

java - super(Application.class); 是什么意思?在Java中?