Мой вопрос основан на ответе на предыдущий вопрос:
Почему мы не можем сделать List <Parent> mylist = ArrayList <child>();
У меня есть функция, которая сортирует список дочерних элементов, который передается ему на основе параметров родительской функции. Поскольку существует много разных типов детей, я написал функцию, которая получает родительский родительский тип.
void sort(ArrayList<? extends Parent> passedList)
Позже в функции я хотел бы обменять два члена (i и j) ArrayList, но я не могу понять, как это сделать. Я пытался:
Parent swap;
swap = passedList.get(i);
passedList.set(i,passedList.get(j));
passedList.set(j,swap);
Однако это не будет компилироваться, и он говорит, что типы не совместимы в заданной функции. Тип, который я получаю от get, является Parent, но set ожидает тип (? Extends Parent). Я также попытался объявить своп как ? extends Parent swap;
? extends Parent swap;
или путем литья, как в
passedList.set(i,(? extends Parent)passedList.get(j));
Похоже, должно быть возможно видеть, как мы можем гарантировать, что объект, возвращенный параметром passList.get(), является правильным типом, который должен принадлежать в arraylist.
Похоже, должно быть возможно видеть, как мы можем гарантировать, что объект, возвращенный параметром passList.get(), является правильным типом, который должен принадлежать в arraylist.
Мы можем сказать, что это правильно, потому что мы можем смотреть на код и отслеживать обратно туда, откуда приходит swap
. Но компилятор не может сказать, потому что язык не гарантирован. Вы пытаетесь поставить Parent
в List<? extends Parent>
List<? extends Parent>
, а в списке может быть некоторый подтип, например List<Child>
.
Вместо этого вы можете выполнить это с помощью подстановочных знаков:
static <P extends Parent> void swap(List<P> list, int i, int j) {
P temp = list.get(i);
list.set(i, list.get(j));
list.set(j, temp);
}
Это позволяет вам выразить, что тип temp
такой же, как и фактический аргумент типа для list
.
Смотрите также:
<? extends Parent>
<? extends Parent>
обещает, что список представляет собой список, содержащий Parents
, или список, содержащий подкласс Parent
, например ArrayList<Child>
.
Это означает, что вы всегда можете получить объект в качестве Parent
, но вы не можете вернуть Parent
туда, поскольку фактический тип списка может быть не Parent
(и вы не можете поместить Parent
в List<Child>
).