大小端的转换一般涉及到跨设备跨系统通信协议的解析和发送中,也根据不同的协议类型有不同的定义.

大小端介绍

  1. 大端(Big-Endian)
    数据的高字节保存在内存的低地址中 数据的低字节保存在内存的高地址中.(低地址存放高位)
    比如:0x12345678,0x12为高字节,如果内存地址为0x4000开始 则 0x12存放在0x4000 0x4001地址存放0x34 …
    作为java的byte数组时:高字节在前,低字节在后,即:0x12 放在 byte数组的0位,0x34 放在 1位 …

  2. 小端(Little-Endian)
    数据的高字节保存在内存的高地址中,而数据的低字节保存在内存的低地址中.(低地址存放低位)
    比如:0x12345678 0x78为低字节,如果内存地址为0x4000开始 则 0x78存放在0x4000 0x4001地址存放0x56 …
    作为java的byte数组时:低字节在前,高字节在后,即:0x78 存放在byte数组的0位 0x56 放在 1 位 …

大小端是针对需要占用多个连续字节的数据,比如short int long,而比如字符串是字符数组,字符是占1个字节,不需要进行大小端转换.
windows,linux,unix的字节序为小端 java则无论平台变化,都是大端

JAVA基础数据类型转化为大小端byte数组

知晓了大小端的规则,对java基本数据类型的处理实际上就只需要取到各个byte进行位置转换即可

  • short,int,lang 这几个类型很简单,进行一些位运算即可:

    /**
    * short转化为小端byte数组
    */
    public static byte[] toLe(short n) {
    byte[] b = new byte[2];
    b[0] = (byte) (n & 0xff);
    b[1] = (byte) (n >> 8 & 0xff);
    return b;
    }

    /**
    * short转为大端byte数组
    */
    public static byte[] toBe(short n) {
    byte[] b = new byte[2];
    b[1] = (byte) (n & 0xff);
    b[0] = (byte) (n >> 8 & 0xff);
    return b;
    }

    /**
    * int转化为小端byte数组
    */
    public static byte[] toLe(int i) {
    byte[] b = new byte[4];
    b[0] = (byte) (i & 0xff);
    b[1] = (byte) (i >> 8 & 0xff);
    b[2] = (byte) (i >> 16 & 0xff);
    b[3] = (byte) (i >> 24 & 0xff);
    return b;
    }

    /**
    * int转化为大端byte数组
    */
    public static byte[] toBe(int n) {
    byte[] b = new byte[4];
    b[3] = (byte) (n & 0xff);
    b[2] = (byte) (n >> 8 & 0xff);
    b[1] = (byte) (n >> 16 & 0xff);
    b[0] = (byte) (n >> 24 & 0xff);
    return b;
    }

    /**
    * long转化为小端byte数组
    */
    public static byte[] toLe(long n) {
    byte[] b = new byte[8];
    b[0] = (byte) (n & 0xff);
    b[1] = (byte) (n >> 8 & 0xff);
    b[2] = (byte) (n >> 16 & 0xff);
    b[3] = (byte) (n >> 24 & 0xff);
    b[4] = (byte) (n >> 32 & 0xff);
    b[5] = (byte) (n >> 40 & 0xff);
    b[6] = (byte) (n >> 48 & 0xff);
    b[7] = (byte) (n >> 56 & 0xff);
    return b;
    }

    /**
    * long转化为大端byte数组
    */
    public static byte[] toBe(long n) {
    byte[] b = new byte[8];
    b[7] = (byte) (n & 0xff);
    b[6] = (byte) (n >> 8 & 0xff);
    b[5] = (byte) (n >> 16 & 0xff);
    b[4] = (byte) (n >> 24 & 0xff);
    b[3] = (byte) (n >> 32 & 0xff);
    b[2] = (byte) (n >> 40 & 0xff);
    b[1] = (byte) (n >> 48 & 0xff);
    b[0] = (byte) (n >> 56 & 0xff);
    return b;
    }
  • float和double确实较为复杂,还好java的保证类型中提供了对应的工具方法

    /**
    * float转化为小端byte数组
    */
    public static byte[] toLe(float f) {
    return toLe(Float.floatToRawIntBits(f));
    }

    /**
    * float转化为大端byte数组
    */
    public static byte[] toBe(float f) {
    return toBe(Float.floatToRawIntBits(f));
    }

    /**
    * double转化为小端byte数组
    */
    public static byte[] toLe(double d) {
    return toLe(Double.doubleToRawLongBits(d));
    }

    /**
    * double转化为大端byte数组
    */
    public static byte[] toBe(double d) {
    return toBe(Double.doubleToRawLongBits(d));
    }

大小端byte数组和java基本类型的互转

byte数组转化为基础数据类型时,也就是按大小端的规则按顺序取到对应字节后进行+操作即可,但是要注意java的byte有符号位,大小范围仅仅为-128-127,当为负数时需要转换

  • 大小端数组转化为short,int,long

    /**
    * 大端byte数组转化为short
    */
    public static short be2Short(byte[] b) {
    int s = 0;
    if (b[0] >= 0) {
    s = s + b[0];
    } else {
    s = s + 256 + b[0];
    }
    s = s << 8;
    if (b[1] >= 0) {
    s = s + b[1];
    } else {
    s = s + 256 + b[1];
    }
    return (short) s;
    }

    /**
    * 小端byte数组转化为short
    */
    public static short le2Short(byte[] b) {
    int s = 0;
    if (b[1] >= 0) {
    s = s + b[1];
    } else {
    s = s + 256 + b[1];
    }
    s = s << 8;
    if (b[0] >= 0) {
    s = s + b[0];
    } else {
    s = s + 256 + b[0];
    }
    return (short) s;
    }

    /**
    * 大端byte数组转化为int
    */
    public static int be2Int(byte[] b) {
    int s = 0;
    if (4 != b.length) return s;
    for (int i = 0; i < 3; i++) {
    if (b[i] >= 0) {
    s = s + b[i];
    } else {
    s = s + 256 + b[i];
    }
    s = s << 8;
    }
    if (b[3] >= 0) {
    s = s + b[3];
    } else {
    s = s + 256 + b[3];
    }
    return s;
    }

    /**
    * 小端byte数组转化为int
    */
    public static int le2Int(byte[] b) {
    int s = 0;
    if (4 != b.length) return s;
    for (int i = 0; i < 3; i++) {
    if (b[3 - i] >= 0) {
    s = s + b[3 - i];
    } else {
    s = s + 256 + b[3 - i];
    }
    s = s << 8;
    }
    if (b[0] >= 0) {
    s = s + b[0];
    } else {
    s = s + 256 + b[0];
    }
    return s;
    }

    /**
    * 大端byte数组转化为long
    */
    public static long be2Long(byte[] b) {
    long s = 0;
    if (8 != b.length) return s;
    for (int i = 0; i < 7; i++) {
    if (b[i] >= 0) {
    s = s + b[i];
    } else {
    s = s + 256 + b[i];
    }
    s = s << 8;
    }
    if (b[3] >= 0) {
    s = s + b[3];
    } else {
    s = s + 256 + b[3];
    }
    return s;
    }

    /**
    * 小端byte数组转化为long
    */
    public static long le2Long(byte[] b) {
    long s = 0;
    if (8 != b.length) return s;
    for (int i = 0; i < 7; i++) {
    if (b[7 - i] >= 0) {
    s = s + b[7 - i];
    } else {
    s = s + 256 + b[7 - i];
    }
    s = s << 8;
    }
    if (b[0] >= 0) {
    s = s + b[0];
    } else {
    s = s + 256 + b[0];
    }
    return s;
    }
  • 大小端数组转化为float和double
    float和double提供的包装类接收的是int和long数据类型,需要把对应位的byte组合为int和long后进行传入

    /**
    * 大端byte数组转化为float
    */
    public static float be2Float(byte[] b) {
    int i = ((((b[0] & 0xff) << 8 | (b[1] & 0xff)) << 8) | (b[2] & 0xff)) << 8 | (b[3] & 0xff);
    return Float.intBitsToFloat(i);
    }

    /**
    * 小端byte数组转化为float
    */
    public static float le2Float(byte[] b) {
    int i = ((((b[3] & 0xff) << 8 | (b[2] & 0xff)) << 8) | (b[1] & 0xff)) << 8 | (b[0] & 0xff);
    return Float.intBitsToFloat(i);
    }

    /**
    * 大端byte数组转化为double
    */
    public static double be2Double(byte[] b) {
    long h = (b[0] & 0xff) << 8;
    h = (h | (b[1] & 0xff)) << 8;
    h = (h | (b[2] & 0xff)) << 8;
    h = (h | (b[3] & 0xff)) << 8;
    h = (h | (b[4] & 0xff)) << 8;
    h = (h | (b[5] & 0xff)) << 8;
    h = (h | (b[6] & 0xff)) << 8;
    h = (h | (b[7] & 0xff));
    return Double.longBitsToDouble(h);
    }

    /**
    * 小端byte数组转化为double
    */
    public static double le2Double(byte[] b) {
    long l = (b[7] & 0xff) << 8;
    l = (l | (b[6] & 0xff)) << 8;
    l = (l | (b[5] & 0xff)) << 8;
    l = (l | (b[4] & 0xff)) << 8;
    l = (l | (b[3] & 0xff)) << 8;
    l = (l | (b[2] & 0xff)) << 8;
    l = (l | (b[1] & 0xff)) << 8;
    l = (l | (b[0] & 0xff));
    return Double.longBitsToDouble(l);
    }

无符号数据类型转化为大小端数组

设计到跨系统传输就肯定会涉及到无符号数据类型,对于java没有无符号类型,不过除了无符号64位以外,对应的无符号类型都可以用java更大范围的基本数据类型表示
无符号8位用short表示,无符号16位用int表示,无符号32位用long表示,8位不需要大小端转换,直接接收即可,主要是进行无符号16和32位的转换:

/**
* 无符号16位转化为小端byte数组
*/
public static byte[] u16ToLe(int n) {
byte[] b = new byte[2];
b[0] = (byte) (n & 0xff);
b[1] = (byte) (n >> 8 & 0xff);
return b;
}

/**
* 无符号16位 转化为大端byte数组
*/
public static byte[] u16ToBe(int n) {
byte[] b = new byte[2];
b[1] = (byte) (n & 0xff);
b[0] = (byte) (n >> 8 & 0xff);
return b;
}

/**
* 无符号32位 转化为小端byte数组
*/
public static byte[] u32ToLe(long n) {
byte[] b = new byte[4];
b[0] = (byte) (n & 0xff);
b[1] = (byte) (n >> 8 & 0xff);
b[2] = (byte) (n >> 16 & 0xff);
b[3] = (byte) (n >> 24 & 0xff);
return b;
}

/**
* 无符号32位 转化为大端byte数组
*/
public static byte[] u32ToBe(long n) {
byte[] b = new byte[4];
b[3] = (byte) (n & 0xff);
b[2] = (byte) (n >> 8 & 0xff);
b[1] = (byte) (n >> 16 & 0xff);
b[0] = (byte) (n >> 24 & 0xff);
return b;
}

大小端数组转化为无符号数据类型

转化为无符号类型时只需要转为对应的有符号类型,再判断是否小于零即可,如果小于零转化为更大数据类型的正数

/**
* 大端byte数组转化为无符号16位(java使用int进行接收)
*/
public static int be2U16(byte[] b) {
short s16 = be2Short(b);
return s16 < 0 ? 65536 + s16 : s16;
}

/**
* 小端byte数组转化为无符号16位(java使用int进行接收)
*/
public static int le2U16(byte[] b) {
short s16 = le2Short(b);
return s16 < 0 ? 65536 + s16 : s16;
}

/**
* 大端byte数组转化为无符号32位(java使用long进行接收)
*/
public static long be2U32(byte[] b) {
int s32 = be2Int(b);
return s32 < 0 ? 4294967296L + s32 : s32;
}

/**
* 小端byte数组转化为无符号32位(java使用long进行接收)
*/
public static long le2U32(byte[] b) {
int s32 = le2Int(b);
return s32 < 0 ? 4294967296L + s32 : s32;
}