有
<!DOCTYPE html>
<html>
<head>
<style>
table {
border-collapse: collapse;
}
th,
td {
border: 1px solid black;
padding: 5px;
text-align: left;
}
</style>
</head>
<body>
<table>
<tr>
<th rowspan="4">Henkilöstöt</th>
<th colspan="3">koulutus</th>
</tr>
<tr>
<td rowspan="3">Muu</td>
<td rowspan="3">Ammattiiiii</td>
<td rowspan="3">korkeakoulu</td>
</tr>
<tr>
</tr>
<tr>
</tr>
<tr>
<td colspan="4">55577855</td>
</tr>
<tr>
<td colspan="4">ikä</td>
</tr>
</table>
</body>
</html>
既然无法做到
class BaseClass implements IData ();
class ChildClassA() extends BaseClass;
class ChildClassB() extends BaseClass;
所以有一个
List<BaseClass> aList = new ArrayList<ChildClassA>()
List<? extends IData> aList
for pointint to either
ArrayList<ChildClassA>(),
or
ArrayList<ChildClassB>()
是在运行时由其他路由构建的,并且该部分代码具有从aList
List<IData>
的功能
问题是aList
是指向List<? extends IData> aList
还是ArrayList<ChildClassA>()
,
可以ArrayList<ChildClassB>()
吗?如下所示:
(似乎它有效,但不确定是否有更好的方法来分配除了强制转换之外的泛型数组。)
编辑: ListData<IData> outputList = (List<IData>) aList
的输出是供只读使用(不可变),没有插入/删除,它只会迭代IData以对IData真正做出反应是
List<IData> outputList
答案 0 :(得分:3)
不,这是不安全的。
在演员之后,添加到应该只包含ChildClassA
个类型元素的列表,另一个子类型ChildClassB
类型的元素,反之亦然,这是合法的。
我们可以简单地使用您的代码,以便更明显地说明为什么不允许这样做:
List<ChildClassA> aList = new ArrayList<ChildClassA>();
aList.add(a1);
aList.add(a2);
//...
List<IData> iDataList = (List<IData>) aList;
iDataList.add(b1);
iDataList.add(b2);
//...
for (ChildClassA a : aList) {
// a some point a is going to be assigned b1 or b2 and they results in cast
// exception.
}
请注意iDataList
引用与aList
完全相同的列表对象。
如果允许该广播,则您可以向aList
个ChildClassA
个实例添加元素。
最好的解决方案是细节。
如果问题是第三方库需要List<IData>
类型的引用,并且只要它只是用于阅读,您可以使用由Collections.unmodifiableList
返回的不可修改的代理:
import java.util.Collections;
//...
final List<ChildClassA> aList = new ArrayList<>();
//... add stuff to aList
final List<IData> readOnlyIDataList = Collections.unmodifiableList(aList);
//... read only access operations readOnlyIDataList
答案 1 :(得分:3)
tl; dr 使用Collections#unmodifiableList
:
List<IData> outputList = Collections.unmodifiableList(aList);
有关此主题的更多信息,您可能希望熟悉PECS原则。
这是不可能的,因为这两种类型是不兼容的。
List<BaseClass>
正是它所声明的内容,是BaseClass
个对象的列表。更确切地说,它有两个保证:
BaseClass
BaseClass
的每个对象添加到其中(而不是其他对象) List<? extends BaseClass>
是一个更宽松的声明。确切地说,它根本不是第二个保证。但是,不仅保证已经消失,而且现在无法向其添加项目,因为列表的确切泛型类型未定义。它甚至可能在运行时更改相同的列表声明(不是相同的列表对象)。
因此,List<? extends BaseClass>
不能分配给List<BaseClass>
,因为后者提供了第一个无法履行的保证。
实际上,请考虑以下方法:
public List<BaseClass> makeList() {
// TODO implement method
return null;
}
如果有人实现此方法,返回List<? extends BaseClass>
,则使用此方法的客户端将无法向其添加项目,尽管其声明另有说明。
因此,这样的赋值会导致编译错误。
要修复示例问题,可以将松散声明添加到方法中:
public List<? extends BaseClass> makeList() {
// TODO implement method
return null;
}
这将向每个客户发出信号,表明从此方法返回的列表不适用于向其添加项目。
现在让我们回到您的用例。在我看来,最合适的解决方法是重新定义
的功能从aList中获取一个List。
因为它似乎现在被宣布为
public void useList(List<BaseClass> list);
但由于它没有将项添加到列表中,因此应将其声明为
public void useList(List<? extends BaseClass> list);
但是,如果该方法是当前不可更改的API的一部分,您仍然可以执行以下操作:
List<? extends BaseClass> list;
....
List<BaseClass> tmp = Collections.unmodifiableList(list);
useList(tmp);