1

List当通过调用获得的子列表的方法对a 进行结构修改时,索引以及索引和列表元素之间的关系会发生什么List.subList(int fromIndex, int toIndex)

我对Oracle JVM 中观察到的事实上的操作不感兴趣;我对接口行为规范感兴趣,因此人们可以可靠地实现自己的列表类(这里的可靠性是指能够通过实现java.util.List接口将Java列表类之一与自己的列表类交换)。

Oracle的文档List似乎并未阐明上述内容。请注意,这与尝试通过子列表以外的任何其他方式修改列表无关,这与通过子列表进行修改有关,正如文档所支持的那样。

例子:

假设我有 6 个元素的列表A, B, C, D, E, F。调用列表会产生一个包含元素B、C、DsubList(1, 4)的子列表。然后我调用这个子列表。我想知道删除后子列表将包含哪些元素?一些替代方案:remove(D)D

  1. B、C、E(子列表保留原来的索引范围)?
  2. B,C(实际上不再是 a subList(1, 4))?

我的猜测是,由于指定了子列表subList(1, 4),因此列表本身的“窗口”必须具有相同的“大小”,E因此可以说滑入视图,因为视图的结束索引仍然是 4,现在D已经过去了E。第二种选择对我来说似乎不是很明智,但仍然是一种选择。

4

4 回答 4

4

以下引用的规范可能会回答这个问题,已在类的文档中java.util.AbstractList找到(有点令人惊讶的是,不在的文档中java.util.List):

此实现返回一个子类 AbstractList 的列表。子类在私有字段中存储子列表在后备列表中的偏移量、子列表的大小(可以在其生命周期内更改)以及后备列表的预期 modCount 值。

从视图大小可以改变的事实来看,索引也可以改变,这意味着在问题中概述的示例场景中,元素不会E“滑入视图”。因此,第二种选择是正确的,因为删除后子列表的大小减少了 1 并且该点的子列表包含 2 个元素。DB, C

部分 Java 设计者可能有意选择在页面中指定上述AbstractList内容,而不是文档页面List- 以便后者保留歧义。但是,我希望实现的两个不同的列表类List在这个特定的细节级别上可以轻松交换和兼容。此外,并非每个List实现都会扩展AbstractList- 这是一种方便,而不是要求。

这是将引用的规范(以及其他一些细节)从AbstractList页面移动到List文档页面。

于 2013-03-10T15:47:09.880 回答
2

由于子列表是 a List,因此删除元素必须减小其大小。此外,该元素还必须从支持列表中删除。(Javadoc 写道:

返回的列表由这个列表支持

返回的列表支持此列表支持的所有可选列表操作。

于 2013-06-23T10:41:07.973 回答
1

List 接口就是契约,不同的实现可以自由地为契约未指定的任何事情做他们喜欢的事情。

它归结为您对短语“在xy之间查看此列表部分的视图”是否有“静态”或“动态”解释- 是对在xysubList之间的支持列表部分的视图在创建子列表时(静态)还是在执行子列表上的每个操作时(动态)?根据合同,这两种读数都是可以接受的,并且可以自由地执行不同的实现。

特别是,合同中没有任何内容remove说删除后列表必须比以前更小,这并不像在多线程或事件侦听器存在的情况下听起来那样奇怪。像这样的案例

// lst contains B, C, D
lst.remove(D);
// lst contains B, C, E

可能是动态的结果,subList也可能是另一个线程将 E 添加到列表中,或者它可能是在元素删除时触发事件并且事件侦听器添加了 E 的列表实现。无论哪种方式都没有破坏 List 契约。

于 2013-06-23T11:00:44.710 回答
0

不出所料,可以在List接口的 Javadoc 中找到答案:

返回的列表由该列表支持,因此返回列表中的非结构性更改会反映在该列表中,反之亦然。返回的列表支持此列表支持的所有可选列表操作。...如果后备列表(即此列表)以除通过返回列表之外的任何方式进行结构修改,则此方法返回的列表的语义变得未定义。

换句话说,可以通过子列表修改列表。

于 2013-06-23T10:35:01.123 回答