todd.run полностью прав, но это только половина ответа. Существуют также варианты использования для выбора <T>
вместо <?>
(или наоборот), которые применяются, когда вы не добавляете параметр типа в класс, который включает метод. Например, рассмотрим разницу между
public <E extends JLabel> boolean add(List<E> j) {
boolean t = true;
for (JLabel b : j) {
if (b instanceof JLabel) {
t = t && labels.add(b);
}
}
return t;
}
и
public boolean add(List<? extends JLabel> j) {
boolean t = true;
for (JLabel b : j) {
if (b instanceof JLabel) {
t = t && labels.add(b);
}
}
return t;
}
Первый метод на самом деле не будет компилироваться, если вы не добавите соответствующий параметр типа в класс включения, тогда как второй метод будет компилироваться независимо от того, имеет ли класс включения параметр типа. Если вы не используете <?>
, то вы несете локальную ответственность за указание компилятору, как получить тип, который будет заполнен буквой, используемой вместо него. Вы часто сталкиваетесь с этой проблемой - нужно использовать? а не T - при попытке написать универсальные методы, которые используют или нуждаются в «extends» и «super». Лучшее, но более сложное решение этой проблемы - на стр. 18 учебного пособия Дженида Брачи (PDF) . Также см. этот вопрос о переполнении стека , ответ на который освещает эти проблемы.
Проверьте эту ссылку переполнения стека для получения информации о вашем втором вопросе: Обобщения Java - стирание типа - когда и что происходит . Хотя я не знаю ответа на ваш вопрос о разнице во времени компиляции между <?>
и <T>
, я почти уверен, что ответ можно найти на этом FAQ , который Эриксон упомянул в этом посте. .