Как получить подмассив массива в Java без копирования данных? - PullRequest
46 голосов
/ 03 августа 2010

У меня есть библиотека классов, которая работает с моими данными и считывается в буфер. Можно ли как-то избежать повторного копирования массивов, передавая части данных все глубже и глубже в методы обработки? Ну, это звучит странно, но в моем конкретном случае есть специальный модуль записи, который разделяет данные на блоки и записывает их по отдельности в разные места, поэтому он просто выполняет System.arraycopy, получает то, что ему нужно, и вызывает базовый модуль записи с этим вложенный массив. И это случается много раз. Каков наилучший подход к рефакторингу такого кода?

Ответы [ 8 ]

62 голосов
/ 03 августа 2010
Arrays.asList(array).subList(x, y).

Этот метод дает вам не массив, а List, который гораздо более гибкий.

21 голосов
/ 03 августа 2010

Многие классы в Java принимают подмножество массивов в качестве параметра. Например. Writer.write (char cbuf [], int off, int len). Может быть, этого уже достаточно для вашего варианта использования.

10 голосов
/ 20 мая 2013

Нет реального способа обернуть любые данные без копирования и получить реальный массив y в Java.Вы просто не можете создать новый массив поверх существующей памяти.У вас есть в основном 2 варианта:

  • Используйте методы, которые могут принимать диапазон массива.Это уже было рекомендовано.
  • Используйте оболочку, которая дает некоторую абстракцию, которая близка к массиву и подходит для многих приложений.Будет описано ниже.

Вы можете использовать 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 (бэкэнд) со всеми элементами.

3 голосов
/ 31 октября 2014

Невозможно объявить подмассив в Java, если вы используете встроенные массивы, такие как byte []. Причина в том, что длина массива хранится вместе с данными, а не с объявлением ссылки на них. Следовательно, у подмассива, который не копирует данные, нет места, где он может хранить длину! Таким образом, для базовых типов вы можете использовать упомянутые эффективные копии байтового массива, а для более высоких типов (List) доступны методы.

2 голосов
/ 03 августа 2010

Вы можете использовать тот же подход, что и класс String;создайте класс для неизменяемых объектов, которые построены из массива, начального смещения и конечного смещения, которые обеспечивают доступ к подмассивуПользователь такого объекта не должен знать различие между целым массивом или вложенным массивом.Конструктор не должен копировать массив, просто сохраните ссылку на массив и его границы.

1 голос
/ 03 апреля 2012

Вы можете использовать (ArrayList) .subList (значение1, значение2), я верю, возможно, это могло бы помочь в вашем случае? Это естественно, если вы хотите использовать ArrayList.

0 голосов
/ 16 мая 2019

Возможно, вместо того, чтобы работать с массивами, вам следует работать с другим типом, который поддерживает ссылку на фрагмент исходного массива, вместо копирования данных, аналогично ArraySegment в C #. Дополнительным преимуществом этого является то, что вы также можете сдвигать срез поверх исходного массива по требованию, не создавая новые экземпляры. Псевдокод:

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 source[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
}
0 голосов
/ 03 августа 2010

Посмотрите на Arrays.copyOfRange(***) методы.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...