泛型:编译器似乎无法识别传递给参数的类型与返回的类型相同 - 为什么?

时间:2010-06-25 18:23:13

标签: java generics type-bounds

假设我有几个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) { ... }

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

GenericDao<? extends BaseContractObject>

而不是认识到getDao(Class<T>)会返回GenericDao相同类型的T

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

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

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

然后编译看起来像

create()实现没有问题
public <T extends BaseContractObject> long create(T object) {
    return getDao(object).save(object);
}

那么为什么编译器能够在这种情况下识别传递给T的{​​{1}}参数在返回类型中是相同的getDao(T),而它在以下时无法识别参数是T

3 个答案:

答案 0 :(得分:5)

表达式object.getClass(),其中对象的类型为T extends BaseObject,返回Class<? extends BaseObject>,而不是Class<T>。因此,getDao()返回的是它收到的相同类型的DAO;它只是没有收到预期的类型。

答案 1 :(得分:2)

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

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

如果您有String并对其进行getClass(),那么您获得的课程为Class<? extends String>。 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);

这适合我。

答案 2 :(得分:0)

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

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