在Java中实现C风格的位域

我有一个问题,我有点困惑,一位同事告诉我,这将是一个寻求帮助的好地方。

我试图在Java中实现C风格的位域。 这是一个粗略的例子(此时我没有在我面前的实际代码)。

typedef union { typedef struct { unsigned short a :1; unsigned short b :1; unsigned short c :2; unsigned short d :10; } bitfield; unsigned short bitmap; }example_bitfield; 

遗留代码中我有一些类似的样式位域。 我需要为Java提供等效方法的原因是我正在研究将使用Java与使用UDP的其他遗留应用程序进行通信的代码。

我没有重写代码的选项。 我知道这种方法不可移植,有字节序问题(和填充/对齐等),并且如果我能够重写代码,可以更好地完成。 不幸的是,我需要回答这个非常具体的问题。 系统已关闭,因此我不需要担心编译器/操作系统等每一种可能的组合。

使用Java EnumSet的方法不起作用,因为我相信只允许每个值为一位。 我需要能够打包值,例如d占用10位的值。

我知道Java Bitset但它有局限性。 我使用的是旧版本的Java,因此我没有一些较新的Java Bitset方法(即可能肯定有帮助的valueOf方法)。

有没有人有任何关于如何使其尽可能易于管理的想法? 我有超过10个位域需要为我的通信实现。

感谢您提供任何帮助!

由于UDP只接受字节数组,因此您可以以任何合适的方式声明java类,唯一关键的步骤是定义序列化和反序列化方法:

 class example_bitfield { byte a; byte b; byte c; short d; public void fromArray(byte[] m) { byte b0=m[0]; byte b1=m[1]; a=b0>>>7; b=(b0>>6)&1; c=(b0>>4)&3; d=(b0&0xF<<6)|(b1>>>2); } public void toArray(byte[] m) { m[0]=(a<<7)|(b<<6)|(c<<4)|(d>>>6); m[1]=(d&0x3F)<<2; } } 

来自Javolution库的Class Struct可满足您的需求( http://www.javolution.org/apidocs/index.html?javolution/io/Struct.html )请参阅“时钟”示例:

  import java.nio.ByteBuffer; class Clock extends Struct { // Hardware clock mapped to memory. Unsigned16 seconds = new Unsigned16(5); // unsigned short seconds:5 Unsigned16 minutes = new Unsigned16(5); // unsigned short minutes:5 Unsigned16 hours = new Unsigned16(4); // unsigned short hours:4 Clock() { setByteBuffer(Clock.nativeBuffer(), 0); } private static native ByteBuffer nativeBuffer(); } 

我最终使用了类似的方法: Java中最有效的方法是打包位

然后我创建了一个包装类,它使用LinkedHashMap存储各个位字段条目。

每个字段都实现为一个存储位数和字段值的类。 该字段的名称是LinkedHashMap的关键。

我添加了开始和结束结构的方法,向结构添加位字段的方法,以及基于键获取和设置值的方法。

我的pack方法遍历LinkedHashMap并在跟踪位偏移的同时放置位(我刚刚使用了一个整数)。

unpack方法还迭代LinkedHashMap并获取位,跟踪位偏移量,并将值存储在LinkedHashMap中。

为方便起见,我编写了将位字段打包为整数,短整数,长整数和字节的方法。 要在字节数组和值之间进行转换,我使用了ByteBuffer并调用了wrap方法。

我还编写了解压缩整数,短,长或字节的方法,方法是首先为数据类型的字节数分配ByteBuffer(4表示整数,2表示整数,ect),然后调用各种put方法ByteBuffer。 一旦我有一个字节数组,我就能将它传递给unpack方法。

我采用这种方法,因为我需要一些自包含,易于使用的东西,这对其他人来说相当容易…我知道可能有更多优雅的方式涉及注释或其他事情(我找到了JavaStruct但是它没有包含位字段。)

从各种原始数据类型打包和解包使我能够更容易地从DataInputStream / DataOutputStream读取和写入结果。

很抱歉,我无法发布代码供所有人使用,因此上述说明必须足够。 希望它能帮助处于类似情况的人:)。

一些粗略的搜索没有透露任何库来使这很容易,但你总是可以通过按位操作手动打包和解包:

 class ExampleBitfield { int bitfield; // actually 16 bits public int getBitfield() { return bitfield; } public void setBitfield(int bitfield) { this.bitfield = bitfield & 0xffff; } // lowest bit public int getA() { return (bitfield >> 0) & 0x01; } public int setA(int a) { return (bitfield & ~0x01) | ((a & 0x01) << 0); } // second lowest bit public int getB() { return (bitfield >> 1) & 0x01; } public int setB(int b) { return (bitfield & ~0x02) | ((b & 0x01) << 1); } // ... }