Объявление общих методов, необходимых разъяснений

Рассмотрим следующие 2 объявления метода:

1. public abstract <T extends MetaData> List<T> execute();
2. public abstract List<? extends MetaData>  execute();

Оба кажутся возвращать список объектов, расширяющих MetaData​​strong > .

В чем разница между ними, пожалуйста?

Ответы

Ответ 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, и вы должны вернуть что-то, относящееся к этому типу. Во втором случае вы просто возвращаете общий тип, но сам метод не имеет общего типа.