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

最后,這也許不是最好的方案,我也不知道是否有更優秀的方案......


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM