У меня есть класс A, и класс B расширяет A
В другом классе C у меня есть поле
private List<B> listB;
Теперь, по некоторой необычной причине, я должен реализовать этот метод в C
public List<A> getList();
Я пытался сделать так, вынуждая восходящее из listB поля Перечислить<A>
с помощью Списка<?>
бросок:
public List<A> getList(){
return (List<A>)(List<?>)listB;
}
Клиенты должны сделать
List<A> list = getList();
for(A a:list){
//do something with a
}
Я сделал некоторый тест, и это кажется работой правильно, но честно я не уверен во всех возможных последствиях.
Это решение правильно? И действительно ли это - лучшее решение?
Спасибо за Ваши ответы.
Нет, это небезопасно. Клиент не должен иметь возможность выполнять
List<A> list = getList();
, потому что в противном случае они могли бы написать
list.add(new C()); // Where C extends A
Тогда исходный код, который знает о списке как List
, будет иметь проблемы когда он пытается его использовать, предполагая, что каждый элемент совместим с B
.
Вы можете либо обернуть исходный список, чтобы он был доступен только для чтения, либо заставить getList
вернуть List extends A>
, что означает, что клиенты все равно не смогут добавлять к нему элементы.
Проблема заключается в том, что клиенты могут невольно вставлять объекты A
только в список более конкретных объектов B
:
c.getList().add(new A());
Это приведет к всевозможным сбоям, когда ваш код попытается взять объект из списка, предполагая, что это B
, но это не так.
Если ваша единственная цель - позволить клиенту перебирать список, лучше вместо этого выдать Iterable
:
public Iterable<A> getAs() { return this.theListOfAs; }
Через этот Iterable
, один может только проверять и удалять элементы, но не добавлять их.
Если вы хотите также отключить удаление, оберните List
Iterable
в свою собственную реализацию, выбрасывая UnsupportedOperationException
при remove () Вызывается
.