如何在Java中获取数组的子数组而不复制数据?
我有一些类库,正在处理我的数据,这些数据正在被读入缓冲区。是否有可能以某种方式避免一次又一次地复制数组,将部分数据越来越深入地传递到处理方法中?嗯,这听起来很奇怪,但在我的特殊情况下,有一个特殊的编写器,它将数据分成块并将它们单独写入不同的位置,因此它只是执行 System.arraycopy,获取它需要的内容并调用底层编写器,使用新的子数组。这种情况发生很多次。重构此类代码的最佳方法是什么?
I have some library of classes, working with my data, which is being read into buffer. Is it possible somehow to avoid copying arrays again and again, passing parts of data deeper and deeper into processing methods? Well, it sounds strange, but in my particular case, there's a special writer, which divides data into blocks and writes them individually into different locations, so it just performs System.arraycopy, gets what it needs and calls underlying writer, with that new sub array. And this happens many times. What is the best approach to refactor such code?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(9)
此方法不会提供数组,而是提供灵活得多的
List
。This method doesn't give you an array, but a
List
, which is far more flexible.Java 中的许多类接受数组的子集作为参数。例如 Writer.write(char cbuf[], int off, int len)。也许这已经足以满足您的用例了。
Many classes in Java accept a subset of an arrays as parameter. E.g. Writer.write(char cbuf[], int off, int len). Maybe this already suffices for your usecase.
在 Java 中,没有真正的方法可以在不复制和接收真实数组的情况下包装任何数据。您只是无法在现有内存上创建新数组。您基本上有 2 个选择:
您可以使用 java.nio.Buffer 类层次结构,尤其是 java.nio.ByteBuffer ,它提供整个数组或子范围的缓冲区抽象。很多时候,这正是人们所需要的。这还提供了许多有趣的功能,例如“零复制”翻转和灵活的字节区域表示。
以下是使用
java 进行包装的示例.nio.ByteBuffer
。这应该非常接近您的需要。至少对于某些操作来说是这样。
然后您可以对
buf
执行任何ByteBuffer
操作。只是警告,
buf.array()
返回包含所有元素的原始a1
数组(后端)。There is no real way to wrap any data without copying and receive real array in Java. You just cannot create new array over existing memory. You have basically 2 options:
You may use
java.nio.Buffer
classes hierarchy, especiallyjava.nio.ByteBuffer
which offers buffer abstraction on whole array or sub-ranges. Often it is what people need. This also offers many interesting abilities like 'zero copy' flip and flexible byte area representation.Here is example of wrapping using
java.nio.ByteBuffer
.This should be very close to what you need. At least for some operations.
Then you can do on
buf
anyByteBuffer
operation.Just a warning,
buf.array()
returns originala1
array (backend) with all elements.如果您使用像 byte[] 这样的内置数组,则无法在 Java 中声明子数组。原因是:数组的长度与数据一起存储,而不是与对其引用的声明一起存储。因此,不复制数据的子数组没有地方可以存储长度!
因此,对于基本类型,您可以使用提到的高效字节数组副本,对于更高类型(列表),有可用的方法。
There is no way to declare a subarray in Java if you use built in arrays like byte[]. The reason is: The length of the array is stored with the data, not with the declaration of the reference to it. Hence a subarray which does not copy the data has no place where it can store the length!
So for basic types you can use the mentioned efficient byte array copies and for higher types (List) there are methods available.
您可以采用与 String 类相同的方法;为不可变对象创建一个类,该类由数组、起始偏移量和结束偏移量构造而成,提供对子数组的访问。这种对象的用户不必知道整个数组或子数组之间的区别。构造函数不必复制数组,只需存储数组引用及其边界。
You could take the same approach as the
String
class takes; create a class for immutable objects which are constructed from an array, a start offset and an end offset which offers access to the sub-array. The user of such an object does not have to know the distinction between the whole array or a sub-array. The constructor does not have to copy the array, just store the array reference and its boundaries.我相信你可以使用 (ArrayList).subList(value1, value2) ,也许这对你的情况有帮助?当然,如果你想使用 ArrayList 的话。
You could use (ArrayList).subList(value1, value2) i belive, perhaps that could help in your case? That is ofcourse if you want to use an ArrayList.
也许您不应该使用数组,而应该使用另一种类型来维护对原始数组切片的引用,而不是复制数据,类似于 C# 中的 ArraySegment。这样做的另一个好处是,您还可以按需将切片转移到原始数组上,而无需创建新实例。伪代码:
Perhaps instead of working with arrays you should work with a different type that maintains a reference to a slice of the original array, instead of copying the data over, similar to ArraySegment in C#. An additional benefit to this is that you can also shift the slice over the original array on-demand, without creating new instances. Pseudo code:
Google 的 Guava 库以 字节源。
Google Guava 是一个现成的开源功能包,从头开始编写,遵循Google 最佳实践,这依赖于重要的数组切片功能。
Google's Guava libraries support the slice concept in the form of a ByteSource.
Google Guava is a readily available open-source package of functionality, written from the ground up to follow Google best practices, which depend on significant array slicing capabilities.
查看 Arrays.copyOfRange(***) 方法。
Have a look on
Arrays.copyOfRange(***)
methods.