从ByteBuffer到对象

时间:2015-10-29 17:08:18

标签: java bytebuffer unsafe

我想将ByteBuffer(来自网络流,并且按照该顺序由<double, double, bool, int>组成)转换为对象,例如给定的类AClass

class AClass {
    public double aDouble;
    public double anotherDouble;
    public boolean aBoolean;
    public int anInteger;
}

我们可以假设,

  • ByteBuffer中每个原始数据类型的大小是已知且常量的(例如double为4个字节,boolean为1个字节)。
  • ByteBuffer中原始数据类型的顺序始终相同。

是否有一种将ByteBuffer转换为给定类对象的高效(类似强制转换)方法?我可以使用某种掩码来掩盖原始数据类型吗?

mask:  | double  | double  |bool| ...
bytes: | - - - - | - - - - | -  | ...

基本上我正在寻找像Matlab's memmapfile这样的功能。非常感谢。

2 个答案:

答案 0 :(得分:4)

您可以使用不安全来执行此操作。它支持直接在本机内存和对象之间复制数据。但是在Java中,您无法控制字段的顺序,也无法控制使用的填充量。例如可以在boolean之后放置int以改善对象的对齐和打包,或者可以在字段之间添加填充。

最好一次复制一个字段。虽然这看起来可能比较慢,但实际上主要问题是将数据带入L1缓存中,相比之下,每个字段的副本相当快。

答案 1 :(得分:2)

从Java 1.0开始,可以通过DataInputStream实现像这样的合理惯用和可维护的方式......

void fillFromBytes(byte[] arr) throws IOException {
  DataInputStream dis = new DataInputStream(new ByteArrayInputStream(arr));
  aDouble = dis.readDouble();
  anotherDouble = dis.readDouble();
  aBoolean = ( dis.readByte() != 0 );
  ...

但是,由于您已经在使用ByteBuffer(自1.4起),因此您可以直接使用一系列方法,例如getDouble()。这为您提供了从任意偏移中读取原始数据的类似方法......

void fillFromBytes(ByteBuffer buf) throws IOException {
  aDouble = buf.getDouble();
  anotherDouble = buf.getDouble();
  aBoolean = ( buf.getByte() != 0 );
  ...

您可以通过跳到其后的绝对位置来处理填充,例如

 anotherDouble = buf.getDouble(0x24);

或一次跳过一个字节:

 int npad = buf.getShort();
 for (int i=0 ; i < npad; i++) buf.getByte();