假设我有几个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
?
答案 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