jbu*_*jbu 180 java arrays slice
我正在寻找一种返回数组片段的Java方法.一个例子是获取包含字节数组的第4和第5个字节的字节数组.我不想在堆内存中创建一个新的字节数组来做到这一点.现在我有以下代码:
doSomethingWithTwoBytes(byte[] twoByteArray);
void someMethod(byte[] bigArray)
{
byte[] x = {bigArray[4], bigArray[5]};
doSomethingWithTwoBytes(x);
}
Run Code Online (Sandbox Code Playgroud)
我想知道是否有一种方法可以做到doSomething(bigArray.getSubArray(4, 2))4是偏移量,2是长度,例如.
Dav*_*ski 184
我不想在堆内存中创建一个新的字节数组来做到这一点.
(老实说,我觉得我的答案值得删除.@ unique72的答案是正确的.Imma让这个编辑坐了一会儿,然后我将删除这个答案.)
我不知道如何直接使用没有额外堆分配的数组,但使用子列表包装器的其他答案只有包装器的附加分配 - 但不是数组 - 这对于一个大阵列.
也就是说,如果一个人正在寻求简洁,那么Arrays.copyOfRange()在Java 6(2006年末?)中引入了实用方法:
byte [] a = new byte [] {0, 1, 2, 3, 4, 5, 6, 7};
// get a[4], a[5]
byte [] subArray = Arrays.copyOfRange(a, 4, 6);
Run Code Online (Sandbox Code Playgroud)
小智 165
Arrays.asList(myArray)委托给new ArrayList(myArray),它不复制数组但只存储引用.List.subList(start, end)之后使用它会产生一个SubList只引用原始列表(它仍然只引用数组).不复制数组或其内容,只创建包装器,所有涉及的列表都由原始数组支持.(我以为它会更重.)
djn*_*jna 39
如果您正在寻找指针样式别名方法,那么您甚至不需要分配空间并复制数据,那么我相信您运气不好.
System.arraycopy() 将从您的源复制到目标,并声明此实用程序的效率.您确实需要分配目标数组.
Sou*_*man 22
一种方法是将数组包装java.nio.ByteBuffer,使用绝对put/get函数,并切片缓冲区以处理子数组.
例如:
doSomething(ByteBuffer twoBytes) {
byte b1 = twoBytes.get(0);
byte b2 = twoBytes.get(1);
...
}
void someMethod(byte[] bigArray) {
int offset = 4;
int length = 2;
doSomething(ByteBuffer.wrap(bigArray, offset, length).slice());
}
Run Code Online (Sandbox Code Playgroud)
请注意,你必须调用这两个wrap()和slice()的,因为wrap()本身仅影响相对PUT/GET功能,而不是绝对的.
ByteBuffer 理解起来可能有点棘手,但最有效的实施,非常值得学习.
Jam*_*hek 20
使用java.nio.Buffer.它是各种原始类型缓冲区的轻量级包装器,有助于管理切片,位置,转换,字节排序等.
如果您的字节源自Stream,则NIO缓冲区可以使用"直接模式",这将创建由本机资源支持的缓冲区.这可以在很多情况下提高性能.
set*_*eth 14
您可以在apache commons中使用ArrayUtils.subarray.不完美但比直观更直观System.arraycopy. 的是它确实在你的代码中引入了另一个依赖.
Car*_*ter 10
我看到subList的答案已经在这里,但这里的代码证明它是一个真正的子列表,而不是副本:
public class SubListTest extends TestCase {
public void testSubarray() throws Exception {
Integer[] array = {1, 2, 3, 4, 5};
List<Integer> list = Arrays.asList(array);
List<Integer> subList = list.subList(2, 4);
assertEquals(2, subList.size());
assertEquals((Integer) 3, subList.get(0));
list.set(2, 7);
assertEquals((Integer) 7, subList.get(0));
}
}
Run Code Online (Sandbox Code Playgroud)
但是,我不相信有一种直接用数组做这个的好方法.
List.subList(int startIndex, int endIndex)
Run Code Online (Sandbox Code Playgroud)
一种选择是传递整个数组以及开始和结束索引,并在它们之间进行迭代,而不是遍历传递的整个数组.
void method1(byte[] array) {
method2(array,4,5);
}
void method2(byte[] smallarray,int start,int end) {
for ( int i = start; i <= end; i++ ) {
....
}
}
Run Code Online (Sandbox Code Playgroud)
在List小号允许您使用和处理的subList东西透明.原始数组需要您跟踪某种偏移 - 限制.ByteBuffer我有类似的选择.
编辑: 如果你负责有用的方法,你可以用bounds定义它(就像在java本身的许多数组相关的方法中所做的那样:
doUseful(byte[] arr, int start, int len) {
// implementation here
}
doUseful(byte[] arr) {
doUseful(arr, 0, arr.length);
}
Run Code Online (Sandbox Code Playgroud)
但是,如果您自己处理数组元素,例如计算某些内容并回写结果,那么目前尚不清楚?
Java引用始终指向一个对象.该对象有一个标题,其中包括标识具体类型(因此强制转换可能会失败ClassCastException).对于数组,对象的开始还包括长度,然后数据紧跟在内存中(技术上,一个实现可以自由地做它喜欢的事情,但是做其他任何事情都是愚蠢的).所以,你可以有一个指向某个数组的引用.
在C指针指向任何地方和任何东西,你可以指向数组的中间.但你不能安全地投射或找出阵列有多长.在D中,指针包含内存块和长度的偏移量(或者等效于指向结尾的指针,我不记得实现实际上做了什么).这允许D切片数组.在C++中,您将有两个指向开始和结束的迭代器,但C++有点奇怪.
所以回到Java,不,你不能.如前所述,NIO ByteBuffer允许您包装数组然后对其进行切片,但是会给出一个尴尬的界面.你当然可以复制,这可能比你想象的要快得多.您可以引入自己String的抽象,允许您对数组进行切片(当前的Sun实现String有一个char[]引用加上一个起始偏移和长度,更高性能的实现就是这样char[]).byte[]是低级别的,但是你提出的任何基于类的抽象都会使语法混乱,直到JDK7(也许).