抓住Java中的数组的一个片段,而无需创建于堆中的新数组抓住Java中的数组的一个片段,而无需创建于

2019-05-31 23:16发布

我正在寻找在Java中的方法,将返回数组的一个片段。 一个例子是用于获得包含一个字节数组的第四和第五字节的字节数组。 我不希望有创建堆内存中一个新的字节数组只是为了做到这一点。 现在,我有以下代码:

doSomethingWithTwoBytes(byte[] twoByteArray);

void someMethod(byte[] bigArray)
{
      byte[] x = {bigArray[4], bigArray[5]};
      doSomethingWithTwoBytes(x);
}

我想知道有没有办法只是做doSomething(bigArray.getSubArray(4, 2))其中4偏移和2的长度,例如。

Answer 1:

免责声明:本答案不符合问题的约束:

我不希望有创建堆内存中一个新的字节数组只是为了做到这一点。

说实话,我觉得我的回答是值得的缺失。通过@ unique72的答案是正确的。伊马让了一下此编辑坐,然后我会删除这个答案。)


我不知道的方式直接与不附加堆分配阵列做到这一点,但使用一个子列表包装其他答案有只包装额外拨款 - 但不是阵列 - 这将是在的情况下有用大阵列。

这就是说,如果一个正在寻找简洁,实用程序方法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);


Answer 2:

Arrays.asList(myArray)委托给新ArrayList(myArray) ,它不会复制数组,但只是存储的参考。 使用List.subList(start, end) ,使一个后SubList这只是引用原始列表(还只是引用数组)。 数组或它的内容,只是包装创作和所有相关名单没有复制由原始数组支持。 (我想那会更重。)



Answer 3:

如果你正在寻找一个指针样式混淆的做法,让你甚至都不需要分配空间和复制数据,那么我相信你的运气了。

System.arraycopy()将从源复制到目标,并且效率声称此实用程序。 你需要分配目的地阵列。



Answer 4:

一种方法是包裹在阵列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());
}

请注意,您必须调用这两个wrap()slice() ,因为wrap()本身仅影响相对PUT / GET功能,而不是绝对的。

ByteBuffer可以是有点棘手理解,但最有可能有效地实现,值得学习。



Answer 5:

使用java.nio.Buffer中的。 它是各种原始类型的缓冲区的一个轻量级封装,并帮助管理切片,位置,转换,字节顺序等。

如果您的字节从Stream起源,NIO的缓冲区可以使用它创建母语资源支持的缓冲区“直接模式”。 这可以在很多情况下提高性能。



Answer 6:

您可以使用ArrayUtils.subarray在Apache的百科全书。 并不完美,但比多一点直观System.arraycopy. 缺点是,它并引入另一个依赖到你的代码。



Answer 7:

我看到子表答案已经在这里,但这里是一个演示,这是一个真正的子表,而不是复制的代码:

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));
    }
}

我不相信有直接与数组做到这一点的好办法,但是。



Answer 8:

List.subList(int startIndex, int endIndex)


Answer 9:

一种办法是通过整个阵列的起点和终点指标,而那些不是迭代通过整个数组之间进行迭代。

void method1(byte[] array) {
    method2(array,4,5);
}
void method2(byte[] smallarray,int start,int end) {
    for ( int i = start; i <= end; i++ ) {
        ....
    }
}


Answer 10:

List小号允许您使用和处理的subList透明的东西。 原始阵列将要求您跟踪某种抵消 - 极限。 ByteBuffer ■找类似的选项,因为我听到了。

编辑:如果你是负责有用的方法,你可以只是界限(如在Java本身的许多阵列相关的方法做定义它:

doUseful(byte[] arr, int start, int len) {
    // implementation here
}
doUseful(byte[] arr) {
    doUseful(arr, 0, arr.length);
}

目前尚不清楚,不过,如果你对数组元素本身,如你计算一些东西,写回结果工作?



Answer 11:

Java的引用总是指向一个对象。 所述对象具有除其他事项标识具体类型(以便强制转换可能失败,头ClassCastException )。 对于数组,对象开始还包括长度,数据再经过紧跟在内存中(在技术上的实现是自由地做它为所欲为,但它是愚蠢做别的事)。 所以,你可以;吨有一个指向到一个数组的地方参考。

在C指针指向任何地方,任何东西,你可以指向一个数组的中间。 但你不能安全地转换或找出数组有多长。 在d的指针包含的偏移到存储器块和长度(或等效的指针端,我不记得什么实现实际上一样)。 这允许d切片阵列。 在C ++中,你将有两个迭代器指向的开始和结束,但C ++是一个有点奇怪这样。

于是又回到了Java的,没有你做不到。 如前所述,NIO ByteBuffer允许您将数组,然后分析它,而是给出了一个尴尬的接口。 你当然也可以拷贝,这可能是非常快很多比你想象。 你可以介绍自己的String式的抽象,它使您能够将一个数组(目前Sun实现的String具有char[]参考加上一个起始偏移量和长度,更高性能的实现才有char[] byte[]为低电平,但你穿上任何基于类的抽象将会使语法的烂摊子,直到JDK7(也许)。



Answer 12:

@ unique72答案作为一个简单的功能或线路,你可能需要更换的对象,你想“片”的相应类别的类型。 两种变型给满足各种需求。

/// 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();
}


Answer 13:

如何薄List包装?

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;
      }
   };
}

(未测试)



Answer 14:

我需要通过一个数组的结尾迭代,不想给阵列复制。 我的方法是使一个可迭代的阵列上。

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");
        }
      };
    }
  };
}


Answer 15:

这比Arrays.copyOfRange多了几分轻巧 - 无范围或负

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;
}


文章来源: Grab a segment of an array in Java without creating a new array on heap