Как назначить списокк списку <BaseClass> - PullRequest
0 голосов
/ 23 мая 2018

с

class BaseClass implements IData ();
class ChildClassA() extends BaseClass;
class ChildClassB() extends BaseClass;

, поскольку не может

List<BaseClass> aList = new ArrayList<ChildClassA>()

, поэтому существует

List<? extends IData> aList 
for pointint to either 
    ArrayList<ChildClassA>(),  
or 
    ArrayList<ChildClassB>()

, aList создается другой маршрутизацией во время выполнения,и эта часть кода имеет функцию для получения List<IData> от aList

вопрос в том, указывает ли List<? extends IData> aList на ArrayList<ChildClassA>() или ArrayList<ChildClassB>(),

это может сделать ListData<IData> outputList = (List<IData>) aList?что-то вроде ниже:

(кажется, это работает, но не уверен, есть ли лучший способ назначить массив generics, отличный от приведения.)

Редактировать: выводиз List<IData> outputList предназначен только для чтения (неизменяемый), без вставки / удаления для него, он будет только повторять IData, чтобы реагировать на то, чем в действительности является IData.

List<? extends IData> aList =  new ArrayList<ChildClassA>();
ListData<IData> outputList = (List<IData>)aList

List<? extends IData> aList =  new ArrayList<ChildClassB>();
ListData<IData> outputList = (List<IData>)aList

Ответы [ 2 ]

0 голосов
/ 23 мая 2018

tl; dr Использование Collections#unmodifiableList:

List<IData> outputList = Collections.unmodifiableList(aList);

Для получения дополнительной информации по этой теме вы можете ознакомиться с Принцип PECS .


Это невозможно, поскольку эти два типа несовместимы.

A List<BaseClass> - это именно то, что объявлено, список BaseClass объектов,Точнее, он дает две гарантии:

  • объекты, извлеченные из него, могут быть назначены на BaseClass
  • каждый объект, который может быть назначен на BaseClass, может быть добавлен к нему (и нетдругое)

A List<? extends BaseClass> - более свободная декларация.Точно, это просто не дает второй гарантии.Однако гарантия не только исчезла, но и теперь невозможно добавить в нее элементы, поскольку точный общий тип списка не определен.Он может даже измениться для того же объявления списка (но не для того же объекта списка) во время выполнения.

Как следствие, List<? extends BaseClass> нельзя назначить для List<BaseClass>, так как последний дает гарантию первомуне может выполнить.


На практике рассмотрим следующий метод:

public List<BaseClass> makeList() {
    // TODO implement method
    return null;
}

Если кто-то реализует этот метод, возвращая List<? extends BaseClass>, клиент, использующий этот метод, будетневозможно добавить элементы к нему, хотя в его объявлении указано иное.

Из-за этого такое присваивание приводит к ошибке компиляции.

Чтобы исправить примерную проблему, к ней может быть добавлено свободное объявление.метод:

public List<? extends BaseClass> makeList() {
    // TODO implement method
    return null;
}

Это будет сигнализировать каждому клиенту, что список, возвращаемый этим методом, не предназначен для добавления элементов в него.


Теперь давайте вернемся к вашему использованиюдело.На мой взгляд, наиболее подходящее исправление - перефразировать функцию, которая

берет [s] List из списка aList.

Как кажется, в настоящее время она объявленакак

public void useList(List<BaseClass> list);

, но поскольку он не добавляет элементы в список, он должен быть объявлен как

public void useList(List<? extends BaseClass> list);

Однако, если этот метод является частью неизменяемого в настоящее время API, вы можетееще делаю:

List<? extends BaseClass> list;
....
List<BaseClass> tmp = Collections.unmodifiableList(list);
useList(tmp);
0 голосов
/ 23 мая 2018

Нет, это небезопасно.

После этого приведения было бы законно добавить в список, который должен содержать только ChildClassA типизированные элементы, элемент другого дочернего типа ChildClassB типа ии наоборот.

Мы можем просто немного добавить ваш код, чтобы сделать более понятным, почему это нельзя допустить:

List<ChildClassA> aList =  new ArrayList<ChildClassA>();
aList.add(a1);
aList.add(a2);
//...
List<IData> iDataList = (List<IData>) aList;
iDataList.add(b1);
iDataList.add(b2);
//...
for (ChildClassA a : aList) {
   // a some point a is going to be assigned b1 or b2 and they results in cast
   // exception.
}

Обратите внимание, что iDataList ссылается на тот же списокобъект как aList.Если бы это приведение было разрешено, то вы могли бы добавить к aList элементы, которые не являются ChildClassA экземплярами.

Лучшее решение заключается в деталях.

Если проблема заключается в том, чтосторонней библиотеке требуется типизированная ссылка List<IData>, и только для чтения вы можете использовать неизменяемый прокси, возвращаемый Collections.unmodifiableList:

import java.util.Collections;
//...
final List<ChildClassA> aList = new ArrayList<>();
//... add stuff to aList
final List<IData> readOnlyIDataList = Collections.unmodifiableList(aList); 
//... read only access operations readOnlyIDataList 
...