Generics: компилятор кажется неспособным распознавать, что тип, передаваемый на аргумент, совпадает с тем, что возвращается - почему?
-
30-09-2019 - |
Вопрос
Скажем, у меня есть несколько пож, которые все распространяют общий супертип, BaseObject
.
у меня есть GenericDao
который объявлен как public interface GenericDao<T>
.
Для каждого типа DAO у меня есть интерфейс, который расширяет общий тип и ограничивает его бетонному типу (public interface UserDao extends GenericDao<User>
) а затем реализация типа конкретной дао.
В классе, которые пытаются использовать ряд 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
Аргумент передан getDao(T)
то же самое T
в возвращении типа, тогда как он не мог распознать это, когда аргумент был Class<T>
?
Решение
Выражение object.getClass()
, где объект имеет тип T extends BaseObject
, возвращает А. Class<? extends BaseObject>
, а не а Class<T>
Как можно ожидать. Так, getDao()
возвращает дао одного и того же типа, который он получает; Это просто не получает ожидаемый тип.
Другие советы
Это проблема стирания классического типа. 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);
Это подходит для меня.
Я думаю, что это должно объяснить, почему ограничение не делает то, что вы ожидаете:
http://www.angelikalanger.com/genericsfaq/faqsions/typeparameters.html#faq206.