我有一个 A 类,B 类扩展了 A
在另一个C类中我有一个字段
private List<B> listB;
现在,由于某些不寻常的原因,我必须在 C 中实现这个方法
public List<A> getList();
我尝试通过 List
<A>
强制将 listB 字段向上转换为 List<?>
来实现此目的:
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>
兼容,那么将列表了解为 B
的原始代码在尝试使用它时将会出现问题。
您可以有效地包装原始列表以使其只读,或者使
getList
返回 List<? extends A>
,这意味着客户端无论如何都无法向其中添加项目。
如果您使用的列表实现是不可修改的,那么它实际上不会导致问题 - 但我个人仍然会尽可能避免它。
这样做的问题是,客户端可能会无意中将
A
对象插入到实际上只是更具体的 B
对象的列表中:
c.getList().add(new A());
当您的代码尝试从列表中获取一个对象(假设该对象是
B
)时,这将导致各种损坏,但事实并非如此。
如果您的唯一目标是让客户迭代列表,最好给出一个
Iterable<A>
:
public Iterable<A> getAs() { return this.theListOfAs; }
通过这个
Iterable
,人们只能检查和删除元素,而不能添加它们。
如果您也想禁用删除,请将
List
的 Iterable
包装在您自己的实现中,在调用 UnsupportedOperationException
时抛出 remove()
。
只需这样做
List<A> getList() {
return List.copyOf(listB);
}
如果你想要可变性,你也可以返回
new ArrayList(listB)
。
正如其他回复所提到的,向上转换集合是不安全的,因为调用者可能会通过将错误的元素放入其中来破坏它。幸运的是,类型系统阻止您这样做,您别无选择,只能使用这些类型良好的方法复制集合,因此它可以正常工作。
也适用于地图。