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
}
Я сделал несколько тестов и, похоже, работает правильно, но, честно говоря, я не уверен в возможных последствиях.
Правильно ли это решение? И это лучшее решение?
Спасибо за ваши ответы.
Ответы
Ответ 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()
.