Объявление общих методов, необходимых разъяснений
Рассмотрим следующие 2 объявления метода:
1. public abstract <T extends MetaData> List<T> execute();
2. public abstract List<? extends MetaData> execute();
Оба кажутся возвращать список объектов, расширяющих MetaDatastrong > .
В чем разница между ними, пожалуйста?
Ответы
Ответ 1
В первом случае вы разрешите Java использовать вывод типа и вывести тип T
на каждом сайте вызова.
Во втором случае вы всегда получите List<? extends MetaData>
и поэтому не сможете назначить его переменной любого более узкого типа типа List<IntegerMetaData>
.
Ответ 2
Если существуют подтипы MetaData
, тогда первая версия может возвращать только пустой список или null
. Вторая версия может возвращать список, содержащий экземпляры MetaData
и его подтипы.
Пример: say A
и B
являются подтипами MetaData
и execute
возвращает список, содержащий экземпляр A
. Вызывающий может вызвать выполнение следующим образом:
List<B> list = execute(); // the second version does not allow this
Абонент сказал, что ему нужен список B
s, но есть список, содержащий A
. Из-за стирания типа реализация execute
не имеет возможности узнать, о чем звонил вызывающий. Таким образом, первая версия не может быть реализована (за исключением возврата null
или пустого списка).
Ответ 3
В примере 1 вы не можете вернуть список, общий тип которого T
, например:
@Override
public <T extends MetaData> List<T> execute() {
List<T> l = new ArrayList<T>();
return l;
}
В примере 2 вы можете вернуть список, общий тип которого равен MetaData
, например:
@Override
public List<? extends MetaData> execute2() {
List<MetaData> l = new ArrayList<MetaData>();
return l;
}
В чем разница? В первом случае метод имеет общий тип T
, и вы должны вернуть что-то, относящееся к этому типу. Во втором случае вы просто возвращаете общий тип, но сам метод не имеет общего типа.