我有一些类的库,可以处理读入缓冲区的数据。有没有办法避免在深层处理方法中一遍又一遍地复制数组并传递数据的部分呢?嗯,这听起来很奇怪,但在我的情况下,有一个特殊的编写器,将数据分成块并单独将它们写入不同的位置,所以它只执行System.arraycopy,获取它需要的内容并调用底层编写器,使用那个新的子数组。而且这种情况发生了很多次。重构这样的代码的最佳方法是什么?
我有一些类的库,可以处理读入缓冲区的数据。有没有办法避免在深层处理方法中一遍又一遍地复制数组并传递数据的部分呢?嗯,这听起来很奇怪,但在我的情况下,有一个特殊的编写器,将数据分成块并单独将它们写入不同的位置,所以它只执行System.arraycopy,获取它需要的内容并调用底层编写器,使用那个新的子数组。而且这种情况发生了很多次。重构这样的代码的最佳方法是什么?
Arrays.asList(array).subList(x, y).
这个方法不会返回一个数组,而是一个List
,它更加灵活。
Arrays.asList(new int[5000])
不会复制吗? - dhardyArrays.asList(new int[]{...})
的类型是 List<int[]>
(所以不是我想要的)。 - dhardyJava中的许多类可以接受数组的子集作为参数。例如,Writer.write(char cbuf[], int off, int len)。也许这已经足够满足您的用例。
在Java中,没有办法不复制数据而接收真正的数组。你不能在现有内存上创建新数组。基本上有两个选择:
您可以使用java.nio.Buffer
类层次结构,特别是java.nio.ByteBuffer
,它为整个数组或子范围提供缓冲区抽象。通常这就是人们所需的。这也提供了许多有趣的能力,如“零拷贝”翻转和灵活的字节区域表示。
下面是使用java.nio.ByteBuffer
进行封装的示例。
这应该非常接近您所需的东西。至少对于某些操作来说是这样。
byte [] a1 = {0, 0, 1, 0};
ByteBuffer buf = ByteBuffer.wrap(a1,1,2);
然后您可以在 buf
上执行任何 ByteBuffer
操作。
只是一个警告, buf.array()
会返回原始的 a1
数组(后端)及其所有元素。
如果您使用内置的字节数组(如byte []),则无法在Java中声明子数组。原因是:数组的长度与数据一起存储,而不是在引用数组时声明。因此,不复制数据的子数组没有地方可以存储其长度!因此,对于基本类型,您可以使用上述高效的字节数组副本,对于更高级的类型(List),有可用的方法。
String
类相同的方法; 创建一个不可变对象的类,该对象由数组、开始偏移量和结束偏移量构建,并提供对子数组的访问。这种对象的使用者不必知道整个数组或子数组之间的区别。构造函数不需要复制数组,只需存储数组引用及其边界即可。public class ArraySegment<T> implements Iterable<T>
{
private int from, to;
private T[] original;
public ArraySegment<T>(T[] original, int from, int to)
{
//constructor stuff
}
public T get(int index)
{
return original[index + from];
}
public int size()
{
return to - from + 1;
}
@Override
public Iterator<T> iterator()
{
//Iterator that iterates over the slice
}
//Can support setters on from/to variables
}
Google的Guava库支持以ByteSource形式实现切片概念。
Google Guava是一个可随时使用的开源功能包,从头开始编写以遵循Google最佳实践,这依赖于重要的数组切片能力。
请查看Arrays.copyOfRange(***)
方法。