当List
通过调用List.subList(int fromIndex, int toIndex)
获得的子列表的方法进行结构修改时,索引和列表元素之间的索引和关系会发生什么?
我对事实上的操作不感兴趣,如Oracle JVM所述;我对接口行为规范很感兴趣,因此可以可靠地实现一个自己的列表类(这里的可靠性是指能够通过实现java.util.List
接口来交换一个Javas列表类与一个自己的列表类。)< / p>
Oracle的documentation of List
似乎没有说明上述情况。请注意,这与尝试通过除子列表之外的任何其他方式修改列表无关,这是关于通过子列表仅修改,正如文档所支持的那样。
说我有一个包含6个元素A, B, C, D, E, F
的列表。在列表上调用subList(1, 4)
会产生一个包含元素 B,C,D 的子列表。然后我在此子列表上调用remove(D)
。我想知道删除D
后子列表中包含哪些元素?一些替代方案:
subList(1, 4)
)?我的猜测是,由于子列表是用subList(1, 4)
指定的,因此列表本身的“窗口”必须是相同的“大小”,因此E
会滑入视图以便说,因为视图的结束索引仍然是4,而D
现在已经超过E
。第二种选择似乎对我来说不是很明智,但不过是另一种选择。
答案 0 :(得分:4)
以下引用的规范可以回答这个问题,已在documentation of java.util.AbstractList
class中找到(有点令人惊讶的是,java.util.List
的文档中不):
此实现返回一个子类AbstractList的列表。子类在私有字段中存储子列表在支持列表中的偏移量,子列表的大小(可以在其生命周期内更改),以及支持列表的预期modCount值。 / p>
由于视图的大小可以改变,因此索引也可以改变,这意味着在问题中概述的示例场景中,元素E
将不“滑入视图”。因此第二种选择是正确的,因为删除D
后子列表的大小减少了1,而该点的子列表包含2个元素B, C
。
可能是Java设计人员的一个深思熟虑的选择,要在AbstractList
页面中指定上述内容,而不是List
的文档页面 - 以便后者保留了模糊性。但是,我希望实现List
的两个不同列表类可以在这个特定的细节级别上轻松交换和兼容。此外,并非每个List
实现都会扩展AbstractList
- 这是一种便利,而不是一项要求。
以下是将引用的规范(以及其他一些详细信息)从AbstractList
页面移至List
文档页面。
答案 1 :(得分:2)
由于子列表是List
,删除元素必须减小其大小。此外,还必须从支持列表中删除该元素。 (Javadoc写道:
返回的列表由此列表支持
和
返回的列表支持此列表支持的所有可选列表操作。
答案 2 :(得分:1)
List接口是合约,不同的实现可以自由地做他们喜欢的合同没有指定的任何内容。
归结为您是否对“ x 和 y 之间的此列表部分视图”这一短语有“静态”或“动态”解释 - 是subList
在创建子列表时(静态)或当时在 x 和 y 之间的支持列表部分的remove
视图子列表上的每个操作都是执行的(动态的)?根据合同,这两个读数都是可以接受的,并且不同的实现都可以自由地进行。
特别是// lst contains B, C, D
lst.remove(D);
// lst contains B, C, E
的合同中没有任何内容表明删除后的列表必须比以前更小,这并不像它的情况那么奇怪在存在多线程或事件监听器时发出声音。像
subList
可能是动态{{1}}的结果,或者它可能是另一个将E添加到列表中的线程,或者它可能是一个列表实现,它触发元素删除事件并且事件侦听器已添加E.无论哪种方式没有什么打破了List合同。
答案 3 :(得分:0)
不出所料,在List界面的Javadoc中找到了答案:
返回的列表由此列表支持,因此返回列表中的非结构更改将反映在此列表中,反之亦然。返回的列表支持此列表支持的所有可选列表操作。 ...如果支持列表(即此列表)在结构上以除返回列表之外的任何方式进行修改,则此方法返回的列表的语义将变为未定义。
换句话说,可以通过子列表修改列表。