如何在不复制的情况下从另一个byte[]的特定位置获取byte[]?

5
在Java中,我想知道如何在不复制的情况下获取特定位置上其他字节数组的字节数组。
例如:
byte[] bytes1 = new byte[100];
for (int i = 0; i < 100; i++) {
    bytes1[i] = (byte)(i+1);
}
byte[] byte2;

如何将byte2指向byte1的第10个位置?我希望byte2是这样的:[0] = 10, [1] = 11, [2] = 12

这可能吗?

我尝试使用ByteBuffer,但没有成功。


1
很遗憾,你不能这样做。也许有一个选项:http://fastutil.di.unimi.it/docs/it/unimi/dsi/fastutil/bytes/ByteList.html#subList(int, int)? - Lyubomyr Shaydariv
@LyubomyrShaydariv 那个实用程序由 List<Byte> 支持,详见我的回答。 - Stefano Sanfilippo
@StefanoSanfilippo 它不是由 List<Byte> 支持的 -- http://grepcode.com/file/repo1.maven.org/maven2/it.unimi.dsi/fastutil/6.5.1/it/unimi/dsi/fastutil/bytes/ByteArrayList.java -- 它有内部的 byte[] a,而不是 Byte[] a。Fastutil 是为高效的原始集合和映射而设计的。 - Lyubomyr Shaydariv
@LyubomyrShaydariv 哎呀,我的错。 - Stefano Sanfilippo
3个回答

4
除了与VM内部搞作(是的,使用JNI调用等指针算术是可能的)之外,唯一的方法是使用类似于Arrays.asList(bytes1).subList(startIndex,endIndex)的方式(请注意,asList()本身不适用于基元数组,您必须编写或在互联网上查找类似于基元的实现;这里想到了http://fastutil.di.unimi.it/docs/it/unimi/dsi/fastutil/bytes/ByteList.html#subList%28int),请注意,通过这种方式您将获得 List 视图,而不是 byte [] ,因为在Java中这基本上是不可能的(除了VM黑客,注意我)。

或者,按照您所说的那样使用java.nio.Buffer,特别是 ByteBuffer ,因为那是指向内存的指针的Java对应物;使用支持数组的 ByteBuffer ,您基本上可以直接访问数组或者以抽象/修改的方式(例如带有偏移量)访问缓冲区。

ByteBuffer bytes1 = ByteBuffer.allocate(100);
for (int i = 0; i < 100; i++) {
    bytes1.put((byte)(i+1));
}
bytes1.position(offset);
ByteBuffer byte2 = bytes1.slice();

甚至更多
byte[] bytes1 = new byte[100];
for (int i = 0; i < 100; i++) {
    bytes1[i] = (byte)(i+1);
}
ByteBuffer bytes1 = ByteBuffer.wrap(bytes1);
bytes1.position(offset);
ByteBuffer byte2 = bytes1.slice();

byte[] bytes = new byte[100]; for (int i = 0; i < 100; i++) { bytes[i] = (byte)(i+1); } ByteBuffer bf1 = ByteBuffer.wrap(bytes); bf1.position(15); ByteBuffer bf2 = bf1.slice(); byte[] byes2 = bf2.array();但是byes2不包含15、16、17。它包含了1、2、3...所以ByteBuffer并没有起到帮助的作用。 - user3668129
1
@user3668129在表示“没有帮助”之前,请先阅读答案和API文档!如果您想使用带有offset(.slice())的ByteBuffer,则必须使用get()或其他ByteBuffer方法,而不是.array() - 支持数组仍然是相同的!这正是为什么我从未在我的代码中使用array()并且说“使用支持数组的ByteBuffer基本上可以直接访问该数组,也可以以抽象/修改的方式访问缓冲区(例如通过偏移量)。”Java中的直接数组访问与抽象(偏移)访问是互斥的! - user719662

3
很遗憾,你不能这样做。你所要求的实质上是C/C++指针算术,而在Java中没有这样的东西。但是,如果你愿意使用不同的接口,你可能会在Commons Primitives ArrayByteList中有一些运气。它不是简单的List<Byte>,因为它由真正的byte数组支持,因此使用Byte对象没有内存开销。你仍然会有一些对象开销,但在实际情况下是可以接受的。

最重要的是,它支持通过 ArrayByteList.subList() 方法进行切片,而该方法不会产生副本。您可以查看源代码,切片是作为对原始数组的引用实现的,加上两个起始和结束位置的标记。

然而,请注意避免复制意味着对切片的更改会反映在原始数组中。这可能是您想要的,但仍需非常小心 - 特别是如果您没有来自 C/C++ 背景,因为这些事情是常见做法。


-1

很抱歉,你不能这样做。

在Java中,每个数组都是一个对象。除了存储元素外,它还存储数组的长度。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接