Let’s say I have several POJOs which all extend a common supertype, BaseObject.
I have a GenericDao which is declared as public interface GenericDao<T>.
For each type-specific DAO, I have an interface which extends the generic type and restricts it to a concrete type (public interface UserDao extends GenericDao<User>) and then an implementation of the type-specific DAO.
In a class that attempts to use a number of GenericDao implementations, I have a method that looks like
public <T extends BaseObject> long create(T object) {
return getDao(object.getClass()).save(object);
}
If I implement getDao() so that it’s parameter is a Class object, such as
private <T extends BaseObject> GenericDao<T> getDao(Class<T> clazz) { ... }
Then the call to getDao(object.getClass() in the create() method fails to compile – the compiler appears to interpret the return type of getDao() as
GenericDao<? extends BaseContractObject>
rather than recognizing that getDao(Class<T>) is going to return me a GenericDao of the same type T.
Can someone explain why this is? I understand that repeated appearances of the same type bound or wildcard don’t necessary refer to the same type; however it seems like the compiler should recognize from the signature of getDao(Class<T>) that the T passed in should be the same T returned (but obviously it isn’t capable of recognizing this, the why is the part I fail to grasp).
If I instead define getDao‘s signature to be
private <T extends BaseContractObject> GenericDao<T> getDao(T obj) { ... }
Then there is no issue in compiling a create() implementation which looks like
public <T extends BaseContractObject> long create(T object) {
return getDao(object).save(object);
}
So why is the compiler capable of recognizing in this case that the T argument passed to getDao(T) is the same T in the return type, whereas it couldn’t recognize this when the argument was Class<T>?
The expression
object.getClass(), where object is of typeT extends BaseObject, returns aClass<? extends BaseObject>, not aClass<T>as one might expect. So,getDao()is returning a DAO of the same type it receives; it’s just not receiving the expected type.