`java.util.List.subList()` 究竟应该如何工作?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/15323694/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-31 19:14:21  来源:igfitidea点击:

How exactly should `java.util.List.subList()` work?

javalist

提问by amn

What happens to indices and relationship between indices and list elements, when a Listis structurally modified through methods of the sub-list obtained through call to List.subList(int fromIndex, int toIndex)?

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

I am not interested in de-facto operationas observed in say, Oracle JVM; I am interested in interface behavior specification so one can implement one's own list classes reliably (reliability here would refer to one being able to swap one of Javas list classes with one's own, by sole virtue of implementing java.util.Listinterface).

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

The documentation of Listby Oracle does not seem to shed light on the above. Mind you, this has nothing to do with attempting to modify the list through any other means than through the sub-list, this is about modification through the sub-list only, as supported by documentation indeed.

Oracle的文档List似乎没有阐明上述内容。你要知道,这已经无关试图通过任何其他方式不是通过子列表修改列表,这是关于通过子列表修改,如文档确实支持。

Example:

例子:

Say I have a list of 6 elements A, B, C, D, E, F. Calling subList(1, 4)on the list yields me a sub-list with elements B, C, D. I then call remove(D)on this sub-list. I would like to know which elements will the sub-list contain after Dis removed? Some alternatives:

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

  1. B, C, E(sub-list retains original index range)?
  2. B, C(effectively no longer a subList(1, 4))?
  1. B、C、E(子列表保留原始索引范围)?
  2. B、C(实际上不再是 a subList(1, 4))?

My guess is that since the sub-list was specified with subList(1, 4)then the "window" on the list itself has to be the same "size", and so Eslides into view so to speak, because the end index of the view is still 4, which with Dnow gone stretches just beyond E. The second alternative does not seem to be very sensible to me, but is an alternative nevertheless.

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

回答by amn

The following quoted specification that may answer the question, has been found in the documentation of java.util.AbstractListclass(and a bit surprisingly, notin documentation of java.util.List):

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

This implementation returns a list that subclasses AbstractList. The subclass stores, in private fields, the offset of the subList within the backing list, the size of the subList (which can change over its lifetime), and the expected modCount value of the backing list.

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

From the fact that the size of the view can change, it follows that the indices can change as well, meaning that in the example scenario outlined in the question, element Ewill not"slide into view". The second alternative is thus correct, as the size of the sub-list after removing Dis reduced by 1 and the sub-list at that point contains 2 elements B, C.

从事实角度的大小可以改变,它遵循的指数可以改变为好,也就是说,在示例场景中的问题,概括元素E不会“陷入观”。因此,第二种选择是正确的,因为删除后子列表的大小D减少了 1,并且此时子列表包含 2 个元素B, C

It may be a deliberate choiceon part of Java designers to specify the above in the AbstractListpage, as opposed to the documentation page of List- so that the latter retains the ambiguity. However, I would expect two different list classes implementing Listto be easily swappable and compatible on this particular level of detail. Also, not every Listimplementation would extend AbstractList- it's a convenience, not a requirement.

可能是一个深思熟虑的选择基于Java的一部分设计人员指定在上面的的AbstractList页面,而不是的文档页面List-让后者保留了不确定性。但是,我希望实现的两个不同的列表类List在这个特定的细节级别上可以轻松交换和兼容。此外,并非每个List实现都会扩展AbstractList- 这是一种方便,而不是要求。

Here is to moving the quoted specification (along with some other details) from AbstractListpage to Listdocumentation page.

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

回答by meriton

Since the sublist is a List, removing an element must reduce its size. Moreover, the element must also be removed from the backing list. (The Javadoc writes:

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

The returned list is backed by this list

返回的列表由此列表支持

and

The returned list supports all of the optional list operations supported by this list.

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

回答by Ian Roberts

The List interface is the contract, and different implementations are free to do what they like for anything the contract doesn't specify.

List 接口就是契约,对于契约没有指定的任何东西,不同的实现可以自由地做他们喜欢的事情。

It boils down to whether you have a "static" or "dynamic" interpretation of the phrase "view of the portion of this list between xand y" - is a subLista view of that portion of the backing list that was between xand yat the time the sublist was created (static) or at the time each operation on the sublist is performed (dynamic)? Both readings would be acceptable as per the contract, and different implementations are free to do either.

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

In particular there's nothing in the contract of removethat says that the list mustbe smaller after the removal than it was before, and this isn't as odd a situation as it sounds in the presence of multi threading or event listeners. A case like

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

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

could be the result of a dynamic subListor it could be another thread adding E to the list, or it could be a list implementation that fires events on element removal and an event listener has added E. Either way nothing has broken the List contract.

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

回答by user207421

The answer is found, unsurprisingly, in the Javadoc for the Listinterface:

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

The returned list is backed by this list, so non-structural changes in the returned list are reflected in this list, and vice-versa. The returned list supports all of the optional list operations supported by this list. ... The semantics of the list returned by this method become undefined if the backing list (i.e., this list) is structurally modified in any way other than via the returned list.

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

In other words the list can be modified via the sublist.

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