C结构体与JavaBean转化

1 概述

(1)项目开发过程可能涉及多种语言,而多种语言之间如何数据交换格式是多种多样的,比如说:Java和JavaScript可以用json,Java和C#可以用xml等等。

(2)这里提供一种C与Java数据交换格式:struct <-> byte[] <-> javaBean

  • C不是一门面向对象的语言,但是C有结构体(struct),C一般操作结构体。
  • Java是一门面向对象的语言,所以Java一般操作对象。
  • 选择byte数组作为传输格式,节省通信成本,没有多余内容,不过极度依赖接收方与发送方之间的配合,毕竟如果字段错乱,将导致解析失败。

2 C语言:struct -> byte[]

#include <stdio.h>
#include <stdlib.h>
#include <mem.h>

struct SS {
    int f;
    int d;
    short g;
}; //结构定义

int main() {
    unsigned char *b; // byte 指针
    int N, i;
    struct SS s = {7, 8, 4}; //声明一个结构对象并初始化
    N = sizeof(struct SS); //结构大小
    b = (unsigned char *) malloc(N); //动态分配b
    memcpy(b, &s, sizeof(struct SS)); //内容复制
    printf("%d", N);
    for (int i = 0; i < N; i++) {
        if (i > 0)
            printf(",");
        printf("%d", b[i]);
    }
    return 0;
}

3 Java语言:byte[] -> JavaBean

(1)方法1:依赖Unsafe类的数组操作接口

public class BytesToBean {
    static class SS {
        private int f;
        private int d;
        private short g;
        // 省略getter和setter 构造方法 toString方法
    }

    private static Unsafe unsafe;

    static {
        try {
            Field f = f = Unsafe.class.getDeclaredField("theUnsafe");
            f.setAccessible(true);
            unsafe = (Unsafe) f.get(null);
        } catch (NoSuchFieldException | IllegalAccessException e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args){
        //struct SS {
        //    int f;
        //    int d;
        //    short g;
        //}; //结构体定义
        byte[] bs = new byte[]{4, 0, 0, 0, 7, 0, 0, 0, 8, 0};
        int offset = 0;
        SS ss = new SS();
        Field[] declaredFields = SS.class.getDeclaredFields();
        for (Field declaredField : declaredFields) {
            Class<?> clazz = declaredField.getType();
            switch (clazz.getTypeName()) {
                case "int":
                    int intValue = unsafe.getInt(bs, Unsafe.ARRAY_BYTE_BASE_OFFSET + offset);
                    unsafe.putInt(ss, unsafe.objectFieldOffset(declaredField), intValue);
                    break;
                case "short":
                    short shortValue = unsafe.getShort(bs, Unsafe.ARRAY_BYTE_BASE_OFFSET + offset);
                    unsafe.putShort(ss, unsafe.objectFieldOffset(declaredField), shortValue);
                    break;
            }
            offset += getFiledLength(clazz);
        }
        System.out.println(ss); // SS{f=4, d=7, g=8}
    }

    private static int getFiledLength(Class clazz){
        Object o = Array.newInstance(clazz, 0);
        return unsafe.arrayIndexScale(o.getClass());
    }

}

(2)方法2:依赖ByteBuffer类的接口

public class BytesToBeans {
    static class SS {
        private int f;
        private int d;
        private short g;
       // 省略getter和setter 构造方法 toString方法
    }

    private static Unsafe unsafe;

    static {
        try {
            Field f = f = Unsafe.class.getDeclaredField("theUnsafe");
            f.setAccessible(true);
            unsafe = (Unsafe) f.get(null);
        } catch (NoSuchFieldException | IllegalAccessException e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        byte[] bs = new byte[]{4, 0, 0, 0, 7, 0, 0, 0, 8, 0};
        ByteBuffer byteBuffer = ByteBuffer.wrap(bs);
        byteBuffer.order(ByteOrder.LITTLE_ENDIAN);
        SS ss = new SS();
        Field[] declaredFields = UnsafeTest.SS.class.getDeclaredFields();
        for (Field declaredField : declaredFields) {
            Class<?> clazz = declaredField.getType();
            switch (clazz.getTypeName()) {
                case "int":
                    int intValue = byteBuffer.getInt();
                    // unsafe.objectFieldOffset(declaredField) 获取该字段的偏移量
                    // Java对象:对象头 常量池数组 字段 方法
                    // 请参考:https://www.cnblogs.com/linzhanfly/p/9552910.html
                    unsafe.putInt(ss, unsafe.objectFieldOffset(declaredField), intValue);
                    break;
                case "short":
                    short shortValue = byteBuffer.getShort();
                    unsafe.putShort(ss, unsafe.objectFieldOffset(declaredField), shortValue);
                    break;
            }
        }
        System.out.println(ss); // SS{f=4, d=7, g=8}
    }
}

4 总结

  • C与Java传输格式为byte数组,总体流程:struct <-> byte[] <-> javaBean。
  • C不熟悉
  • Java依赖Unsafe的对象字段赋值操作API、反射机制和ByteBuffer的byte数组操作API

最后,这也许不是最好的方案,我也不知道是否有更优秀的方案......

posted @ 2018-10-15 21:13  月下小魔王  阅读(3178)  评论(2编辑  收藏  举报