• 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

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

  • 相关阅读:
    WIF基本原理(4)联合身份验证实例
    Open XML应用安全(4)文档校验
    WIF基本原理(5)WIF的功能简介
    Open XML应用安全(3)隐藏数据
    WIF基本原理(3)安全令牌服务
    Open XML应用安全(5)数字签名
    Open XML应用安全(1)宏安全
    WIF基本原理(2)基于声明的标识模型
    搭建基于Android和PhoneGap的开发环境
    定位flash上传出现IO Error #2038的错误
  • 原文地址:https://www.cnblogs.com/linzhanfly/p/9794752.html
Copyright © 2020-2023  润新知