Подтвердить что ты не робот

Upcast из списка <подкласs> в список <суперкласs> через List <?>

У меня есть класс A, а класс B расширяет A

В другом классе C у меня есть поле

private List<B> listB;

Теперь по какой-то необычной причине я должен реализовать этот метод в C

public List<A> getList();

Я попытался сделать это, запустив uplist из поля listB в List <A> с помощью List <?> cast:

public List<A> getList(){
    return (List<A>)(List<?>)listB;
}

Клиенты должны делать

List<A> list = getList();
for(A a:list){
    //do something with a
}

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

Правильно ли это решение? И это лучшее решение?

Спасибо за ваши ответы.

4b9b3361

Ответ 1

Нет, это не безопасно. Клиент не должен делать

List<A> list = getList();

потому что иначе они могли бы написать

list.add(new C()); // Where C extends A

Тогда исходный код, который знает о списке как List<B>, будет иметь проблемы, когда он попытается его использовать, считая, что каждый элемент совместим с B.

Вы можете либо обернуть исходный список, чтобы сделать его доступным только для чтения, либо сделать getList return a List<? extends A>, что означает, что клиенты все равно не смогут добавлять элементы к нему.

Ответ 2

Проблема заключается в том, что клиенты могут, невольно, вставлять объекты A в то, что на самом деле является списком более конкретных объектов B:

c.getList().add(new A());

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

Если ваша единственная цель - позволить клиенту перебирать список, лучше передать вместо него Iterable<A>:

public Iterable<A> getAs() { return this.theListOfAs; }

С помощью этого Iterable можно только проверять и удалять элементы, но не добавлять их.

Если вы хотите также отключить удаление, оберните List Iterable в свою собственную реализацию, выбросив UnsupportedOperationException, когда вызывается remove().