在Java中获取数组的一段,而无需在堆上创建新数组
我正在寻找一个Java方法,它将返回数组的一段。例如,获取包含字节数组第4和第5个字节的字节数组。我不想为了实现这一点就必须在堆内存中创建一个新的字节数组。现在我有以下代码:在Java中获取数组的一段,而无需在堆上创建新数组,java,arrays,slice,Java,Arrays,Slice,我正在寻找一个Java方法,它将返回数组的一段。例如,获取包含字节数组第4和第5个字节的字节数组。我不想为了实现这一点就必须在堆内存中创建一个新的字节数组。现在我有以下代码: doSomethingWithTwoBytes(byte[] twoByteArray); void someMethod(byte[] bigArray) { byte[] x = {bigArray[4], bigArray[5]}; doSomethingWithTwoBytes(x); }
doSomethingWithTwoBytes(byte[] twoByteArray);
void someMethod(byte[] bigArray)
{
byte[] x = {bigArray[4], bigArray[5]};
doSomethingWithTwoBytes(x);
}
我想知道是否有一种方法可以只做
doSomething(bigArray.getsubray(4,2))
,其中4是偏移量,2是长度。列表允许您透明地使用和使用子列表。基元数组需要跟踪某种偏移限制ByteBuffer
s的选项与我听说的类似
List.subList(int startIndex, int endIndex)
编辑:
如果您负责这个有用的方法,您可以用边界来定义它(就像java中许多与数组相关的方法一样:
doUseful(byte[] arr, int start, int len) {
// implementation here
}
doUseful(byte[] arr) {
doUseful(arr, 0, arr.length);
}
但是,目前还不清楚您是否处理数组元素本身,例如,您计算了一些内容并写回结果?如果您正在寻找指针样式的别名方法,这样您甚至不需要分配空间和复制数据,那么我相信您运气不好
System.arraycopy()
将从您的源复制到目标,并要求此实用程序具有效率。您确实需要分配目标阵列。我看到子列表的答案已经在这里,但下面的代码表明它是真正的子列表,而不是副本:
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));
}
}
public类SubListTest扩展了TestCase{
public void testSubarray()引发异常{
整数[]数组={1,2,3,4,5};
列表=数组。asList(数组);
列表子列表=列表。子列表(2,4);
assertEquals(2,subList.size());
assertEquals((整数)3,subList.get(0));
列表。集合(2,7);
assertEquals((整数)7,subList.get(0));
}
}
但是,我不认为有一种直接使用数组的好方法。您可以在apache commons中使用。这并不完美,但比System.arraycopy更直观。
缺点是它会在代码中引入另一个依赖项。一个选项是传递整个数组以及起始和结束索引并在它们之间迭代,而不是在传递的整个数组上迭代
void method1(byte[] array) {
method2(array,4,5);
}
void method2(byte[] smallarray,int start,int end) {
for ( int i = start; i <= end; i++ ) {
....
}
}
void方法1(字节[]数组){
方法2(阵列,4,5);
}
void method2(字节[]smallarray,int start,int end){
对于(inti=start;i使用java.nio.Buffer's。它是各种基本类型缓冲区的轻量级包装器,有助于管理切片、位置、转换、字节排序等
如果您的字节来自流,NIO缓冲区可以使用“直接模式”,创建由本机资源支持的缓冲区。这在很多情况下都可以提高性能。Java引用始终指向对象。该对象有一个标头,其中包括一个标识具体类型的标头(因此,使用ClassCastException
)强制转换可能会失败。对于数组,对象的开头还包括长度,然后数据紧跟在内存中(从技术上讲,实现可以随心所欲,但做任何其他事情都是愚蠢的)。因此,不能有指向数组某处的引用
在C语言中,指针指向任何地方,指向任何东西,你可以指向数组的中间。但是你不能安全地强制转换或找出数组的长度。在D语言中,指针包含内存块的偏移量和长度(或者相当于指向末尾的指针,我不记得实现的实际功能)在C++中,你会有两个迭代器指向开始和结束,但是C++有点奇怪。
回到Java,不,你不能。如前所述,NIOByteBuffer
允许你包装一个数组,然后对它进行切片,但它提供了一个笨拙的界面。你当然可以复制,这可能比你想象的要快得多。你可以引入你自己的字符串
-样的抽象,允许你对数组进行切片(当前Sun实现的String
有一个char[]
引用,加上一个起始偏移量和长度,更高性能的实现只有char[]
)。byte[]
是低级的,但是任何基于类的抽象都会使语法变得非常混乱,直到JDK7(也许).免责声明:此答案不符合问题的约束条件:
我不想为了实现这一点就必须在堆内存中创建一个新的字节数组
(老实说,我觉得我的答案值得删除。@unique72的答案是正确的。伊玛让这个编辑停一下,然后我将删除这个答案。)
我不知道有什么方法可以在没有额外堆分配的情况下直接使用数组来实现这一点,但是使用子列表包装器的其他答案只对包装器进行了额外的分配,而不是对数组进行分配,这在大型数组的情况下非常有用
这就是说,如果你想要简洁,实用方法是在Java 6中引入的(2006年底?):
Arrays.asList(myArray)
委托给新的ArrayList(myArray)
,它不复制数组,只存储引用。使用List.subList(start,end)
之后,创建一个只引用原始列表(仍然只引用数组)的子列表。无需复制数组或其内容,只需创建包装器,所有涉及的列表都由原始数组支持。(我认为它会更重。)薄的列表
包装器怎么样
List<Byte> getSubArrayList(byte[] array, int offset, int size) {
return new AbstractList<Byte>() {
Byte get(int index) {
if (index < 0 || index >= size)
throw new IndexOutOfBoundsException();
return array[offset+index];
}
int size() {
return size;
}
};
}
List getsubraylist(字节[]数组,整数偏移量,整数大小){
返回新的AbstractList(){
字节获取(int索引){
如果(索引<0 | |索引>=大小)
抛出新的IndexOutOfBoundsException();
返回数组[偏移量+索引];
}
int size(){
List<Byte> getSubArrayList(byte[] array, int offset, int size) {
return new AbstractList<Byte>() {
Byte get(int index) {
if (index < 0 || index >= size)
throw new IndexOutOfBoundsException();
return array[offset+index];
}
int size() {
return size;
}
};
}
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());
}
public static final byte[] copy(byte[] data, int pos, int length )
{
byte[] transplant = new byte[length];
System.arraycopy(data, pos, transplant, 0, length);
return transplant;
}
/// Extract out array from starting position onwards
public static Object[] sliceArray( Object[] inArr, int startPos ) {
return Arrays.asList(inArr).subList(startPos, inArr.length).toArray();
}
/// Extract out array from starting position to ending position
public static Object[] sliceArray( Object[] inArr, int startPos, int endPos ) {
return Arrays.asList(inArr).subList(startPos, endPos).toArray();
}
public static Iterable<String> sliceArray(final String[] array,
final int start) {
return new Iterable<String>() {
String[] values = array;
int posn = start;
@Override
public Iterator<String> iterator() {
return new Iterator<String>() {
@Override
public boolean hasNext() {
return posn < values.length;
}
@Override
public String next() {
return values[posn++];
}
@Override
public void remove() {
throw new UnsupportedOperationException("No remove");
}
};
}
};
}