【问题标题】:Generics: Compiler seems incapable of recognizing that the type passed to an argument is the same as what is returned - why?泛型:编译器似乎无法识别传递给参数的类型与返回的类型相同 - 为什么?
【发布时间】:2010-06-25 18:23:13
【问题描述】:

假设我有几个 POJO,它们都扩展了一个公共超类型 BaseObject

我有一个GenericDao,它被声明为public interface GenericDao<T>

对于每个特定类型的 DAO,我都有一个接口,它扩展了泛型类型并将其限制为具体类型 (public interface UserDao extends GenericDao<User>),然后是特定类型 DAO 的实现。

在一个尝试使用多个 GenericDao 实现的类中,我有一个看起来像这样的方法

public <T extends BaseObject> long create(T object) {
    return getDao(object.getClass()).save(object);
}

如果我实现getDao() 使其参数是Class 对象,例如

private <T extends BaseObject> GenericDao<T> getDao(Class<T> clazz) { ... }

然后在create() 方法中对getDao(object.getClass() 的调用无法编译 - 编译器似乎将getDao() 的返回类型解释为

GenericDao<? extends BaseContractObject>

而不是认识到getDao(Class&lt;T&gt;) 将返回给我一个相同类型的GenericDao T

有人可以解释这是为什么吗?我了解重复出现的相同类型绑定或通配符不一定指相同类型;但是似乎编译器应该从getDao(Class&lt;T&gt;) 的签名中识别出传入的 T 应该与返回的 T 相同(但显然它无法识别这一点,why 是部分我没掌握)。

如果我改为将getDao 的签名定义为

private <T extends BaseContractObject> GenericDao<T> getDao(T obj) { ... }

那么编译create() 实现就没有问题了

public <T extends BaseContractObject> long create(T object) {
    return getDao(object).save(object);
}

那么为什么编译器在这种情况下能够识别传递给getDao(T)T 参数在返回类型中与T 相同,而当参数为Class&lt;T&gt; 时它无法识别这一点?

【问题讨论】:

    标签: java generics type-bounds


    【解决方案1】:

    表达式object.getClass()(其中对象的类型为T extends BaseObject)返回Class&lt;? extends BaseObject&gt;,而不是人们可能期望的Class&lt;T&gt;。所以,getDao() 返回一个与它接收到的相同类型的 DAO;它只是没有收到预期的类型。

    【讨论】:

    • 这很有道理,谢谢。我忘了 getClass() 会返回通配符类型
    【解决方案2】:

    这是一个经典的类型擦除问题。 getClass() 具有以下签名:

    public final native Class<? extends Object> getClass();
    

    如果你有一个String 并在上面做一个getClass(),你得到的课程是Class&lt;? extends String&gt;。 javadocs 阅读:

     * @return The <code>java.lang.Class</code> object that represents
     *         the runtime class of the object.  The result is of type
     *         {@code Class<? extends X>} where X is the
     *         erasure of the static type of the expression on which
     *         <code>getClass</code> is called.
    

    您需要强制执行以下强制转换才能使其工作:

    @SuppressWarnings("unchecked")
    Class<T> clazz = (Class<T>)object.getClass();
    return getDao(clazz).save(object);
    

    这对我有用。

    【讨论】:

      【解决方案3】:

      我认为这应该可以解释为什么约束没有达到您的预期:

      http://www.angelikalanger.com/GenericsFAQ/FAQSections/TypeParameters.html#FAQ206

      【讨论】:

      • 恐怕它没有回答这个问题。我没有尝试访问T.class;我的问题是为什么编译器无法识别类型绑定&lt;T extends BaseObject&gt; 意味着我的输入参数Class&lt;T&gt; 中的T 将引用与返回类型GenericDao&lt;T&gt; 中的T 相同的类型。
      猜你喜欢
      • 1970-01-01
      • 2018-12-24
      • 1970-01-01
      • 2020-06-30
      • 2019-08-15
      • 2010-11-15
      • 1970-01-01
      • 2013-07-17
      • 1970-01-01
      相关资源
      最近更新 更多