Generics: Компилятор кажется неспособным распознать, что тип, передаваемый в аргумент, совпадает с тем, что возвращается - почему? - PullRequest
1 голос
/ 25 июня 2010

Допустим, у меня есть несколько 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, такойas

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 (но, очевидно, он не способен это распознать, , почему является частью Iне понять).

Если я вместо этого определю сигнатуру 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, переданный getDao(T), совпадает с T в возвращаемом типе, тогда как он не смог распознать это, когда аргумент былClass<T>

Ответы [ 3 ]

5 голосов
/ 25 июня 2010

Выражение object.getClass(), где объект имеет тип T extends BaseObject, возвращает Class<? extends BaseObject>, а не Class<T>, как можно было бы ожидать. Таким образом, getDao() возвращает DAO того же типа, который получает; он просто не получает ожидаемый тип.

2 голосов
/ 25 июня 2010

Это проблема стирания классического типа. 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);

Это работает для меня.

0 голосов
/ 25 июня 2010

Я думаю, это должно объяснить, почему ограничение не делает то, что вы ожидаете:

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

...