我有一些二进制对象,如byte[]
,在对其进行一些计算之前,需要将它们转换为float[]
。
我当前的方法如下:
bytes[] binaryData;
float[] docVector = new float[vectorSize];
ByteBuffer.wrap(binaryData).asFloatBuffer().get(docVector);
这确实有效,但是据我了解它会创建原始数组的副本,是否有可能获得一个指向二进制数组相同内存地址的float数组?例如,在python和numpy中,可以执行以下操作以获取内存中相同数据的视图:
import numpy as np
binary_data = np.zeros(40, dtype=np.uint8)
float_array = binary_data.view(np.float32)
答案 0 :(得分:2)
Java是一种繁重的面向对象语言。除了很少的原始类型之外,Java中的所有内容都是对象。
Java中的数组不能使用。与其他语言(例如C或C ++)不同,数组不是简单分配给原始类型的内存。它们是完整的完整对象,继承自java.lang.Object
。
通过以下示例代码,这变得显而易见:
float[] foo = new float[] {1, 2, 3, 4};
byte[] bla = new byte[] {1, 2, 3, 4};
System.out.println(foo.getClass());
System.out.println(bla.getClass());
因此,即使有一种将byte[]
重新解释/转换为float[]
的方法,它也会给您带来损坏的对象,因为您没有转换基础的基本类型数组,但是整个对象,并且不能保证它们的大小相同或基础数据以相同的偏移量存储。
由于Java无法获得共享相同基础二进制数据的两个不同的数组对象,因此有两种选择:
创建副本。由于某些(过时的)Java实现在调用ByteBuffer.toFloatBuffer()
时会创建一个副本,因此您可能要检查是否已经创建了副本:
float[] docVector;
FloatBuffer floatBuffer = ByteBuffer.wrap(binaryData).asFloatBuffer();
if (floatBuffer.hasArray()) {
docVector = floatBuffer.array(); // Avoids copying twice
}
else
docVector = new float[vectorSize];
floatBuffer.get(docVector);
}
根据您的工作,直接使用FloatBuffer
而不是创建新的float[]
数组就足够了。您可以以类似的方式迭代浮动对象,具体取决于您的用例和目标平台,这是内存与性能的决定。
答案 1 :(得分:2)
在Java中是不可能的。
执行类似操作的唯一方法是使用我们的Flyweight模式
编辑
我错误地使用了名称“ Flyweight”(由于@AdrianShum)。 我的意思是这样的课:
class FloatArray {
byte[] buff;
void set(int index, float value) { ... }
float get(int index) { ... }
}
答案 2 :(得分:-2)
您可以将字节读取到输入流中,并从输入流中读取浮点数。
byte [] bytesArray = new byte[120]; //array of your bytes.
ByteInputStream bytesStream = new ByteInputStream(bytesArray, bytesArray.length);
DataInputStream dataStream = new DataInputStream(bytesStream);
float[] floats = new float[bytesArray.length / 4]; //float is 4 bytes. Make sure than the number of bytes can be divided by 4.
for (int i = 0;i < floats.length; i++) {
floats[i] = dataStream.readFloat();
}
如果查看ByteInputStream
的来源,您会发现它没有创建缓冲区的副本。
java.io.ByteInputStream
public ByteArrayInputStream(byte buf[], int offset, int length) {
this.buf = buf;
this.pos = offset;
this.count = Math.min(offset + length, buf.length);
this.mark = offset;
}
更新
将分配两个n个字节的数组。 n
的一个数组是您的输入字节数组,另一个是输出float数组。如果您不想为输出数组分配内存,但是例如您需要一个个地访问这些元素,则可以创建一个索引。
class FloatIndex {
private byte[] buffer;
private ByteInputStream bytesStream;
private int nFloats;
private int count = 0;
public FloatIndex(byte[] buffer) {
this.buffer = buffer;
ByteInputStream bytesStream = new ByteInputStream(buffer, buffer.length);
if (buffer.length % 4 != 0) {
throw new IllegalArgumentException("This buffer does not have floats");
}
nFloats = buffer.length / 4;
}
public float nextFloat() {
DataInputStream dataStream = new DataInputStream(bytesStream);
if (count > nFloats) {
throw new RuntimeException("There are no more floats");
}
try {
float f = dataStream.readFloat();
count++;
return f;
} catch (IOException e) {
throw new RuntimeException("Failed to read float.", e);
}
}
public boolean hasNext() {
return count > nFloats;
}
}