在Java中创建子数组列表而不进行复制

5
我将尝试从一个数组中初始化ArrayList,但只包括子数组,给定原始数组和子数组的起始和结束索引。
我只能想到像这样从子数组创建新列表:
Arrays.asList(Arrays.copyOfRange(arr, i, j));

或者手动将元素添加到列表中。
List<Integer> result = new ArrayList<>(k);
for (int i = left; i < left + k; i++) {
    result.add(arr[i]);
}

很明显这样并不美观。有没有更好的方法只通过传递数组和索引来实现?

要求我们推荐或寻找书籍、工具、软件库、教程或其他外部资源的问题,因为它们往往会吸引有偏见的答案和垃圾邮件,所以在 Stack Overflow 上是不适合的。相反,请描述问题以及已经采取的解决方法。 - user177800
2
@JarrodRoberson 这与什么相关呢? - shmosel
2
@JarrodRoberson 谢谢提醒。我更新了问题,使其更加通用。 - Armo
1个回答

12

“更好”的选择取决于您的要求和用例。由于您建议使用返回固定大小列表的Arrays.asList(...),因此我将在此假设对于您的需求来说,固定大小的列表已足够。

可能最快的方法是使用

Arrays.asList(arr).subList(i, j);
这很快,因为没有将任何元素复制到其他位置,也没有进行迭代。 Arrays.asList(arr) 实际上创建了一个列表,它是原始数组的包装器,subList(...) 则创建了一个现有列表的视图。
这样做的权衡(总会有权衡)是它保留了对原始数组的引用。因此,如果您要生成大量的大型数组,并想保留每个数组的一小部分,这对于内存消耗来说将是一个不良选择。(相反,如果您有一个大型数组,并想要大量不同且可能重叠的切片,那么这将是一种非常节省内存且速度快的方法。)
如果内存考虑使您需要释放对原始数组的任何引用,则必须以某种方式复制元素到新结构中。可能最有效的方法是使用您建议的方法:Arrays.copyOfRange(...) 基本上委托给 System.arrayCopy(...),它在大多数系统上基本上是以本地方式实现的(连续的内存块的批量复制),然后像之前一样,Arrays.asList(...) 只是为那个新数组创建了一个列表包装器。因此,在您想释放对原始数组的引用的情况下,您建议的方式是最有效的。
Arrays.asList(Arrays.copyOfRange(arr, i, j));

很可能是“最佳”方法。


1
另一个权衡是由Arrays.asList返回的列表有点不可变,即您既不能添加也不能删除其中的元素,但可以在特定位置设置一个元素。 - fps
@FedericoPeraltaSchaffner 是的,确实;我有点认为这符合OP的要求,因为他们建议使用Arrays.asList(...)来解决问题。但你是正确的,应该明确说明。 - James_D

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接