如何分配List <?将BaseClass>扩展为List <BaseClass>

lan*_*nyf 5 java generics list-template

class BaseClass implements IData ();
class ChildClassA() extends BaseClass;
class ChildClassB() extends BaseClass;
Run Code Online (Sandbox Code Playgroud)

既然做不到

List<BaseClass> aList = new ArrayList<ChildClassA>()
Run Code Online (Sandbox Code Playgroud)

所以有一个

List<? extends IData> aList 
for pointint to either 
    ArrayList<ChildClassA>(),  
or 
    ArrayList<ChildClassB>()
Run Code Online (Sandbox Code Playgroud)

aList是通过其他路由在运行时建立,并且该代码部分具有如下功能:取List<IData>从所述aList

问题是如果List<? extends IData> aList 指向ArrayList<ChildClassA>()ArrayList<ChildClassB>(),

可以ListData<IData> outputList = (List<IData>) aList吗?如下所示:

(似乎它正在工作,但不确定是否有更好的方法来分配除了强制转换之外的泛型数组.)

编辑:输出List<IData> outputList 是为了只读使用(不可变),没有插入/删除,它只会迭代IData以对IData真正的反应作出反应.

List<? extends IData> aList =  new ArrayList<ChildClassA>();
ListData<IData> outputList = (List<IData>)aList

List<? extends IData> aList =  new ArrayList<ChildClassB>();
ListData<IData> outputList = (List<IData>)aList
Run Code Online (Sandbox Code Playgroud)

Izr*_*ruo 3

TL;博士使用Collections#unmodifiableList

List<IData> outputList = Collections.unmodifiableList(aList);
Run Code Online (Sandbox Code Playgroud)

有关此主题的更多信息,您可能想熟悉PECS原理。


这是不可能的,因为这两种类型不兼容。

AList<BaseClass>正如它所声明的那样,是一个BaseClass对象列表。更准确地说,它做出了两个保证:

  • 从它检索的对象可分配给BaseClass
  • 每个可分配的对象都BaseClass可以添加到其中(不能添加其他对象)

AList<? extends BaseClass>是一个更宽松的声明。准确地说,它根本不做第二次保证。然而,不仅保证消失了,而且现在不可能向其中添加项目,因为列表的确切通用类型未定义。它甚至可能在运行时更改相同的列表声明(不是相同的列表对象)。

因此, aList<? extends BaseClass>不可分配给 a List<BaseClass>,因为后者做出了第一个无法实现的保证。


实际上,可以考虑以下方法:

public List<BaseClass> makeList() {
    // TODO implement method
    return null;
}
Run Code Online (Sandbox Code Playgroud)

如果有人实现此方法并返回 a List<? extends BaseClass>,则使用此方法的客户端将无法向其中添加项目,尽管其声明另有说明。

因此,这样的赋值会导致编译错误。

要解决示例问题,可以将松散声明添加到方法中:

public List<? extends BaseClass> makeList() {
    // TODO implement method
    return null;
}
Run Code Online (Sandbox Code Playgroud)

这将向每个客户端发出信号,表明从此方法返回的列表并不用于向其中添加项目。


现在让我们回到您的用例。在我看来,最合适的解决方法是重新表述该函数

从 aList 中取出一个列表。

目前看来它被声明为

public void useList(List<BaseClass> list);
Run Code Online (Sandbox Code Playgroud)

但由于它不会将项目添加到列表中,因此应将其声明为

public void useList(List<? extends BaseClass> list);
Run Code Online (Sandbox Code Playgroud)

但是,如果该方法是当前不可更改的 API 的一部分,您仍然可以执行以下操作:

List<? extends BaseClass> list;
....
List<BaseClass> tmp = Collections.unmodifiableList(list);
useList(tmp);
Run Code Online (Sandbox Code Playgroud)