闲着无聊,写了一个对象转换成byte[]的工具类,支持整型按位写入(大大节省空间),具体步骤如下:
1. 定义实体类和注解- public class User {
- /**
- * ID,4个字节,32bit
- */
- @JSONField(ordinal = 1)
- @BitPos(offset=0,size = 32)
- public int id;
- /**
- * 姓名,10个字节(80bit)
- */
- @JSONField(ordinal = 2)
- @BitPos(offset = 32, size= 80)
- public String name;
- /**
- * 性别,0:男,1:女,1Bit
- */
- @JSONField(ordinal = 3)
- @BitPos(offset = 112, size = 1)
- public int sex;
- /**
- * 年龄,最大127,7Bit
- */
- @JSONField(ordinal = 4)
- @BitPos(offset = 113, size=7)
- public int age;
- /**
- * 身高,最大2^10-1=1023cm,10Bit
- */
- @JSONField(ordinal = 5)
- @BitPos(offset = 120, size = 10)
- public int height;
- /**
- * 体重,最大2^10-1=1023kg,10Bit
- */
- @JSONField(ordinal = 6)
- @BitPos(offset = 130, size = 10)
- public int weight;
- /**
- * 多少个月的薪水,最大2^4-1=15个月薪,4Bit
- */
- @JSONField(ordinal = 7)
- @BitPos(offset = 140, size=4)
- public int monthSalary;
- /**
- * 地址:20字节,160bit
- */
- @JSONField(ordinal = 8)
- @BitPos(offset = 144, size = 160)
- public String address;
- }
复制代码- @Retention(RetentionPolicy.RUNTIME)
- @Target(ElementType.FIELD)
- public @interface BitPos {
- /**
- * 位置(占总长度的位置)
- */
- int offset() default -1;
- /**
- * 长度(多少bit)
- */
- int size() default -1;
- }
复制代码 2. 工具类
[code]/** * 对象转位字节(整型实现按bit写入,字符串则按字节写入) * * 时间: 2024/1/23 11:12 */public class ObjToBitBytesUtil { public static void main(String[] args) throws IllegalAccessException, UnsupportedEncodingException { User user = new User(); user.id = 10001; user.name = "张三"; user.sex = 0; user.age = 18; user.height = 170; user.weight = 50; user.monthSalary = 13; user.address = "浙江杭州西湖"; System.out.println("原始对象:"); System.out.println(JSON.toJSONString(user, SerializerFeature.WriteNullStringAsEmpty)); //对象写成字节数组 byte[] bytes = writeObjToBitBytes(user, 38); System.out.println("对象的字节数组16进制表示:"); printHex(bytes); //字节数组转成对象 User readUser = readBitBytesToObj(bytes); System.out.println("字节数组转换成的对象:"); System.out.println(JSON.toJSONString(readUser,SerializerFeature.WriteNullStringAsEmpty)); } private static User readBitBytesToObj(byte[] bytes) throws IllegalAccessException, UnsupportedEncodingException { User user = new User(); Field[] fields = user.getClass().getFields(); for (Field field : fields) { BitPos bitPos = field.getAnnotation(BitPos.class); Object val = readField(bytes, field, bitPos.offset(), bitPos.size()); field.set(user,val); } return user; } private static Object readField(byte[] buffer, Field field, int offset, int size) throws UnsupportedEncodingException { Object val = null; if(field.getType().equals(int.class) || field.getType().equals(Integer.class)){ // 整型,按位读取 int valInt = 0; //起始缓存位置(第几个字节,从0开始) int startBufferIndex = offset / 8; //起始字节已经占用了多少bit int startByteUsedBit = offset % 8; int startByteRemainBit = 8 - startByteUsedBit; //结束缓存位置(第几个字节) int endBufferIndex = (offset + size - 1) / 8; int endByteUseBit = ((offset + size - 1) % 8)+1; // 缓存间隔位置(缓存起止位置之间的间隔字节数) int gapByteCount = endBufferIndex - startBufferIndex - 1; // 1. 读取起始字节(读高位) byte lowerByte = buffer[startBufferIndex]; lowerByte = (byte) (lowerByte >>> startByteUsedBit); int mask = (1 0) { for (int i = 0; i < gapByteCount; i++) { int leftMove = startByteRemainBit + (i * 8); byte b = buffer[startBufferIndex+(i+1)]; valInt |= (b startBufferIndex) { byte b = buffer[endBufferIndex]; int leftMove = startByteRemainBit + gapByteCount * 8; mask = (1 startBufferIndex) { int rightMove = startByteRemainBit + gapByteCount * 8; mask = (1 > rightMove) & mask); } } else { // 字符串直接按字节写入 byte[] bytes = val.toString().getBytes("utf-8"); int actualByteCount = bytes.length; int startBufferIndex = offset / 8; int endBufferIndex = startBufferIndex + size/8-1; int byteIndex = 0; for(int i = startBufferIndex; i |