Я ищу метод в Java, который будет возвращать сегмент массива. Примером может быть получение байтового массива, содержащего 4-й и 5-й байты байтового массива. Я не хочу создавать новый массив байтов в памяти кучи только для этого. Прямо сейчас у меня есть следующий код:
doSomethingWithTwoBytes(byte[] twoByteArray);
void someMethod(byte[] bigArray)
{
byte[] x = {bigArray[4], bigArray[5]};
doSomethingWithTwoBytes(x);
}
Я хотел бы знать, был ли способ просто сделать, doSomething(bigArray.getSubArray(4, 2))
где 4 - это смещение, а 2 - это длина, например.
Ответы:
Отказ от ответственности: Этот ответ не соответствует ограничениям вопроса:
( Честно говоря, я чувствую, что мой ответ заслуживает удаления. Ответ @ unique72 правильный. Имма, пусть это изменение займет некоторое время, а затем я удалю этот ответ. )
Я не знаю способа сделать это напрямую с массивами без дополнительного выделения кучи, но другие ответы, использующие оболочку подсписка, имеют дополнительное выделение только для оболочки - но не для массива - что было бы полезно в случае большой массив.
Тем не менее, если кто-то ищет краткость,
Arrays.copyOfRange()
в Java 6 был представлен служебный метод (конец 2006 года?):источник
copyOfRange
. Если бы это был закрытый источник, возможно, это могло бы пройти. :)Arrays.asList(myArray)
делегирует newArrayList(myArray)
, который не копирует массив, а просто хранит ссылку. ИспользованиеList.subList(start, end)
после этого делаетSubList
который просто ссылается на исходный список (который все еще просто ссылается на массив). Никакое копирование массива или его содержимого, только создание обертки, и все вовлеченные списки поддержаны оригинальным массивом. (Я думал, что это будет тяжелее.)источник
Arrays
вызывающе смущающем вызовеArrayList
, но который на самом деле представляетList
собой массив, в отличие отjava.util.ArrayList
которого можно было бы сделать копию. Нет новых распределений (содержимого списка) и сторонних зависимостей. Это, я считаю, самый правильный ответ.byte[]
в его случае). Все, что вы получите, будетList<byte[]>
. И измененияbyte[] bigArray
вByte[] bigArray
может наложить значительные накладные расходы памяти.sun.misc.Unsafe
класс.Если вы ищете подход с псевдонимами в стиле указателя, так что вам даже не нужно выделять пространство и копировать данные, то я считаю, что вам не повезло.
System.arraycopy()
будет копировать из вашего источника в пункт назначения, и эффективность этой утилиты заявлена. Вам нужно выделить массив назначения.источник
array*copy*()
повторно использовать ту же память? Разве это не полная противоположность ожидания абонента?Одним из способов является завернуть массив в
java.nio.ByteBuffer
, использовать абсолютные функции put / get и нарезать буфер для работы с подмассивом.Например:
Обратите внимание, что вы должны вызывать и то
wrap()
и другоеslice()
, посколькуwrap()
само по себе влияет только на относительные функции put / get, а не на абсолютные.ByteBuffer
может быть немного сложным для понимания, но, скорее всего, эффективно реализовано и заслуживает изучения.источник
StandardCharsets.UTF_8.decode(ByteBuffer.wrap(buffer, 0, readBytes))
Arrays.copyOfRange
?Arrays.copyOfRange
вероятно, более эффективен. Как правило, вам придется измерять для вашего конкретного случая использования.Используйте java.nio.Buffer's. Это облегченная оболочка для буферов различных примитивных типов, которая помогает управлять нарезкой, позицией, преобразованием, упорядочением байтов и т. Д.
Если ваши байты происходят из потока, буферы NIO могут использовать «прямой режим», который создает буфер, поддерживаемый собственными ресурсами. Это может улучшить производительность во многих случаях.
источник
Вы можете использовать ArrayUtils.subarray в Apache Commons. Не идеальный, но немного более интуитивный, чем
System.arraycopy.
недостаток в том, что он вводит другую зависимость в ваш код.источник
Я вижу, что ответ подсписка уже здесь, но вот код, который демонстрирует, что это настоящий подсписок, а не копия:
Однако я не верю, что есть хороший способ сделать это напрямую с массивами.
источник
источник
Они
List
позволяют вам использовать и работать сsubList
чем-то прозрачным. Примитивные массивы требуют, чтобы вы отслеживали какой-то предел смещения.ByteBuffer
У меня есть похожие варианты, как я слышал.Редактировать: если вы отвечаете за полезный метод, вы можете просто определить его с помощью границ (как это делается во многих связанных с массивом методах в самой java:
Однако не ясно, работаете ли вы над самими элементами массива, например, что-то вычисляете и записываете результат?
источник
Одним из вариантов будет передача всего массива и индексов начала и конца и итерация между ними вместо перебора всего переданного массива.
источник
Ссылки Java всегда указывают на объект. У объекта есть заголовок, который среди прочего идентифицирует конкретный тип (поэтому приведение может завершиться неудачно с
ClassCastException
). Для массивов начало объекта также включает в себя длину, после чего данные следуют сразу же после того, как в памяти (технически реализация свободна делать то, что ей нравится, но было бы глупо делать что-либо еще). Таким образом, вы не можете иметь ссылку, которая указывает где-то в массив.В C указатели указывают куда угодно и на что угодно, и вы можете указывать на середину массива. Но вы не можете безопасно разыграть или узнать, как долго массив. В D указатель содержит смещение в блоке памяти и длину (или эквивалентно указатель на конец, я не могу вспомнить, что на самом деле делает реализация). Это позволяет D нарезать массивы. В C ++ у вас было бы два итератора, указывающих на начало и конец, но C ++ немного странный.
Вернемся к Java, нет, вы не можете. Как уже упоминалось, NIO
ByteBuffer
позволяет вам обернуть массив и затем нарезать его, но дает неудобный интерфейс. Вы можете, конечно, копировать, что, вероятно, намного быстрее, чем вы думаете. Вы могли бы представить свою собственнуюString
абстракцию, подобную той, которая позволяет вам разрезать массив (текущая реализация SunString
имеетchar[]
ссылку плюс начальное смещение и длину, а реализация с более высокой производительностью просто имеетchar[]
).byte[]
это низкий уровень, но любая основанная на классах абстракция, которую вы надеваете, будет сильно портить синтаксис до JDK7 (возможно).источник
substring
в HotSpot (забудьте, какая сборка изменила это). Почему вы говорите, что JDK7 допускает лучший синтаксис, чем ByteBuffer?[]
нотацию массива для пользовательских типов, таких какList
иByteBuffer
. Все еще жду ...@ unique72 в качестве простой функции или строки, вам может потребоваться заменить Object на соответствующий тип класса, который вы хотите «нарезать». Два варианта даны для удовлетворения различных потребностей.
источник
Как насчет тонкой
List
обертки?(Непроверенные)
источник
Byte
объекты для всехbyte
значений кэшируются. Так что накладные расходы на бокс должны быть довольно медленными.Мне нужно было перебрать конец массива и не хотел копировать массив. Мой подход состоял в том, чтобы сделать Iterable по массиву.
источник
Это немного легче, чем Arrays.copyOfRange - без диапазона или отрицательный
источник