将 List<SubClass> 转换为 List<BaseClass 的最有效方法>

2022-08-31 07:33:56

我有一个我想被视为.这似乎不应该是一个问题,因为将 a 强制转换为 a 是一个快照,但我的编译器抱怨强制转换是不可能的。List<SubClass>List<BaseClass>SubClassBaseClass

那么,获取对与对象相同的对象的引用的最佳方法是什么?List<BaseClass>

现在我只是制作一个新列表并复制旧列表:

List<BaseClass> convertedList = new ArrayList<BaseClass>(listOfSubClass)

但据我所知,必须创建一个全新的列表。如果可能的话,我想参考原始列表!


答案 1

此类赋值的语法使用通配符:

List<SubClass> subs = ...;
List<? extends BaseClass> bases = subs;

重要的是要认识到 a 不能与 .保留对 的引用的代码将期望列表中的每个项都是 .如果代码的另一部分将列表称为 a,则在插入 或 时编译器不会抱怨。但这将导致 第一段代码为 a,该代码假定列表中的所有内容都是 .List<SubClass>List<BaseClass>List<SubClass>SubClassList<BaseClass>BaseClassAnotherSubClassClassCastExceptionSubClass

泛型集合的行为与 Java 中的数组不同。数组是协变的;也就是说,允许这样做:

SubClass[] subs = ...;
BaseClass[] bases = subs;

这是允许的,因为数组“知道”其元素的类型。如果有人尝试在数组中存储不是 的实例的内容(通过引用),将引发运行时异常。SubClassbases

泛型集合“知道”它们的组件类型;此信息在编译时被“擦除”。因此,当发生无效存储时,它们无法引发运行时异常。相反,当从集合中读取值时,将在代码中某个很远、难以关联的点引发 a。如果您注意编译器有关类型安全的警告,则可以在运行时避免这些类型错误。ClassCastException


答案 2

埃里克森已经解释了为什么你不能这样做,但这里有一些解决方案:

如果只想从基列表中删除元素,原则上应将接收方法声明为采用 .List<? extends BaseClass>

但是,如果不是,并且您无法更改它,则可以使用 包装列表,这允许返回参数参数的超类型的列表。(它通过在插入尝试时引发不受支持的操作异常来避免类型安全问题。Collections.unmodifiableList(...)


推荐