Toma un segmento de una matriz en Java sin crear una nueva matriz en el montón

Estoy buscando un método en Java que devuelva un segmento de una matriz. Un ejemplo sería obtener la matriz de bytes que contiene los 4tos y 5tos bytes de una matriz de bytes. No quiero tener que crear una nueva matriz de bytes en la memoria del montón solo para hacer eso. En este momento tengo el siguiente código:

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

Me gustaría saber si hay alguna manera de hacer algo doSomething(bigArray.getSubArray(4, 2)) donde 4 es el desplazamiento y 2 es la longitud, por ejemplo.

    Descargo de responsabilidad: esta respuesta no se ajusta a las limitaciones de la pregunta:

    No quiero tener que crear una nueva matriz de bytes en la memoria del montón solo para hacer eso.

    ( Honestamente, siento que mi respuesta es digna de ser eliminada. La respuesta de @ unique72 es correcta. Dejo que esta edición se quede un rato y luego eliminaré esta respuesta. )


    No sé de una forma de hacer esto directamente con arreglos sin asignación de montón adicional, pero las otras respuestas que usan un contenedor de sublista tienen una asignación adicional solo para el contenedor, pero no para el conjunto, que sería útil en el caso de una gran variedad

    Dicho esto, si uno está buscando la brevedad, el método de utilidad Arrays.copyOfRange() se introdujo en Java 6 (finales de 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); 

    Arrays.asList(myArray) delega en la nueva ArrayList(myArray) , que no copia la matriz, sino que almacena la referencia. El uso de List.subList(start, end) después de eso SubList una SubList que solo hace referencia a la lista original (que aún hace referencia a la matriz). No se copia el conjunto o sus contenidos, solo se crea el contenedor, y todas las listas implicadas están respaldadas por el conjunto original. (Pensé que sería más pesado.)

    Si está buscando un enfoque de alias de estilo de puntero, para que ni siquiera necesite asignar espacio y copiar los datos, entonces creo que no tiene suerte.

    System.arraycopy() copiará de su origen a destino, y se reclama la eficacia para esta utilidad. Necesitas asignar la matriz de destino.

    Una forma es envolver la matriz en java.nio.ByteBuffer , usar las funciones absoluta put / get y cortar el búfer para trabajar en un subcampo.

    Por ejemplo:

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

    Tenga en cuenta que debe llamar tanto a wrap() como a slice() , ya que wrap() solo afecta a las funciones relativas put / get, no a las absolutas.

    ByteBuffer puede ser un poco difícil de entender, pero lo más probable es que se implemente de manera eficiente, y vale la pena aprenderlo.

    Use java.nio.Buffer’s. Es un envoltorio liviano para buffers de varios tipos primitivos y ayuda a administrar el corte, la posición, la conversión, el orden de bytes, etc.

    Si sus bytes se originan en un flujo, los búferes de NIO pueden usar el “modo directo” que crea un búfer respaldado por recursos nativos. Esto puede mejorar el rendimiento en muchos casos.

    Puede usar ArrayUtils.subarray en apache commons. No es perfecto, pero es un poco más intuitivo que System.arraycopy. La desventaja es que introduce otra dependencia en su código.

    Veo que la respuesta de la sublista ya está aquí, pero aquí hay un código que demuestra que es una verdadera sublista, no una copia:

     public class SubListTest extends TestCase { public void testSubarray() throws Exception { Integer[] array = {1, 2, 3, 4, 5}; List list = Arrays.asList(array); List 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)); } } 

    Sin embargo, no creo que haya una buena forma de hacerlo directamente con las matrices.

     List.subList(int startIndex, int endIndex) 

    Una opción sería pasar toda la matriz y los índices de inicio y fin, e iterar entre ellos en lugar de iterar sobre toda la matriz pasada.

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

    Las subList le permiten usar y trabajar con subList de algo de forma transparente. Las matrices primitivas requieren que realice un seguimiento de algún tipo de compensación – límite. ByteBuffer s tiene opciones similares a las que escuché.

    Editar: si está a cargo del método útil, puede definirlo con límites (como se hace en muchos métodos relacionados con matrices en java mismo:

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

    Sin embargo, no está claro si trabajas en los elementos de la matriz, p. Ej., ¿Computas algo y escribes el resultado?

    Las referencias de Java siempre apuntan a un objeto. El objeto tiene un encabezado que, entre otras cosas, identifica el tipo concreto (por lo que los moldes pueden fallar con ClassCastException ). Para las matrices, el inicio del objeto también incluye la longitud, los datos se siguen inmediatamente después en la memoria (técnicamente una implementación es libre de hacer lo que le plazca, pero sería tonto hacer cualquier otra cosa). Por lo tanto, no puede tener una referencia que apunte a alguna parte de una matriz.

    En los punteros C apunte a cualquier lugar y a cualquier cosa, y puede señalar el centro de una matriz. Pero no puedes lanzar con seguridad ni saber cuánto tiempo dura la matriz. En D, el puntero contiene un desplazamiento en el bloque y la longitud de la memoria (o, de forma equivalente, un puntero al final, no puedo recordar qué hace realmente la implementación). Esto permite a D cortar matrices. En C ++ tendrías dos iteradores apuntando al inicio y al final, pero C ++ es un poco raro así.

    Así que volviendo a Java, no, no puedes. Como se mencionó, NIO ByteBuffer te permite envolver una matriz y luego cortarla, pero ofrece una interfaz incómoda. Por supuesto, puede copiar, que probablemente sea mucho más rápido de lo que cree. Podría introducir su propia abstracción tipo String que le permita cortar una matriz (la implementación actual de Sun de String tiene una referencia char[] más un desplazamiento y longitud de inicio, una implementación de mayor rendimiento solo tiene el char[] ). byte[] es de bajo nivel, pero cualquier abstracción basada en clase que pongas va a hacer un lío terrible de la syntax, hasta JDK7 (tal vez).

    @ unique72 responde como una simple función o línea, puede que necesite reemplazar Objeto, con el tipo de clase respectivo que desea ‘cortar’. Se dan dos variantes para satisfacer diversas necesidades.

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

    ¿Qué tal un envoltorio de List delgada?

     List getSubArrayList(byte[] array, int offset, int size) { return new AbstractList() { Byte get(int index) { if (index < 0 || index >= size) throw new IndexOutOfBoundsException(); return array[offset+index]; } int size() { return size; } }; } 

    (No probado)

    Necesitaba iterar hasta el final de una matriz y no quería copiar la matriz. Mi enfoque era hacer un Iterable sobre la matriz.

     public static Iterable sliceArray(final String[] array, final int start) { return new Iterable() { String[] values = array; int posn = start; @Override public Iterator iterator() { return new Iterator() { @Override public boolean hasNext() { return posn < values.length; } @Override public String next() { return values[posn++]; } @Override public void remove() { throw new UnsupportedOperationException("No remove"); } }; } }; } 

    Esto es un poco más ligero que Arrays.copyOfRange – sin rango o negativo

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

    Por favor use

     System.arrayCopy(); 

    Le permite especificar la posición de inicio en la matriz fuente y la cantidad de elementos que desea copiar.