Implementing a C style bitfield in Java

孤人 提交于 2019-12-01 05:19:07

Since UDP accepts only byte arrays, you can declare java class in any suitable way and the only critical step is to define serialization and deserialization methods:

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;
  }
}

Class Struct from Javolution library makes what you need (http://www.javolution.org/apidocs/index.html?javolution/io/Struct.html) See "Clock" example:

 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();
 }
shadowisadog

I ended up using a similar approach presented here: What is the most efficent way in Java to pack bits

And then I made a wrapper class that uses LinkedHashMap to store the individual bit field entries.

Each field was implemented as a class that stores the number of bits and the value of the field. The name of the field is the key to the LinkedHashMap.

I added methods for starting and ending a structure, a method to add a bit field to the structure, and methods for getting and setting values based on keys.

My pack method iterates through the LinkedHashMap and puts the bits while keeping track of the bit offset (I just used an integer for this purpose).

The unpack method also iterates the LinkedHashMap and gets the bits, keeping track of the bit offset, and storing the values in the LinkedHashMap.

For convenience I wrote methods for packing the bit fields to integers, shorts, longs, and a byte. To convert between the byte array and the values I used a ByteBuffer and called the wrap method.

I also wrote methods for unpacking a packed integer, short, long, or byte by first allocating the ByteBuffer for the number of bytes that the data type has (4 for integer, 2 for short, ect) and then calling the various put methods of the ByteBuffer. Once I had a byte array I was able to pass that to the unpack method.

I went with this approach because I needed something self contained, that was easy to work with, and that was fairly easy for other people to follow... I know there are probably more elegant ways involving annotations or other things (I found JavaStruct but it didn't incorporate bit fields.)

Packing and unpacking from various primitive data types enable me to read and write the results from a DataInputStream/DataOutputStream easier.

I am sorry that I am unable to post the code for everyone to benefit from, so the above explanation will have to suffice. Hopefully it will help someone in a similar situation :).

Some cursory searching didn't reveal any libraries to make this easy, but you could always pack and unpack things by hand with bitwise operations:

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);
    }

    // ...
}
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!