两个例子理解主机字节序和网络字节序,不同平台字节序转换

不同平台存储多字节整形数据的内存顺序不同,分为主机字节序和网络字节序分别对应小端字节序和大端字节序

Java平台存储多字节整形时是大端字节序,如存储int i=0x01020304 在内存中的顺序是 01 02 03 04。先占位高内存,后占位低内存。即数值的高位存储在低内存上

c++ windows平台下是低端字节序 int i=0x01020304 在内存中的顺序是 04 03 02 01。先占位低内存后占位高内存,即数值的高位存储在高内存上

网络和JVM都采用的是大字节序,这种字节序符合人类的习惯。JVM会根据底层的操作系统和CPU自动进行字节序的转换

int i= 0x01020304在Java平台上存储顺序是01 02 03 04,发送后c+ +平台接收到的顺序是01 02 03 04 放到内存中的顺序也是 01 02 03 04,但是在c+ +平台识别 01 02 03 04 代表的int时,是以按照 int j = 0x04 03 02 01 按这个顺序拼好的数将这四字节内存识别为int类型。

举两个例子来理解一下

  • 定义一个int值10000,分别查看在不同平台下的内存排序
//java平台下:
public static void main(String args[]) {
private static final char[] HEX_CHAR = {'0','1','2','3','4','5','6','7','8','9','a','b', 'c', 'd', 'e', 'f'};
int x = 10000;
//用ByteBuffer类将int转为byte数组,这种情况下是按照实际内存中的字节顺序输出,也就是大端字节序
//bb.order(ByteOrder.LITTLE_ENDIAN);此方法可以将输出的数组由大端字节序转为小端字节序排列
ByteBuffer bb = ByteBuffer.wrap(new byte[4]);
bb.asIntBuffer().put(x);
String hex = bytesToHexFun1(bb.array());
System.out.println(hex);
}

//byte数组转十六进制字符串
public static String bytesToHex(byte[] bytes) {
    char[] buf = new char[bytes.length * 2];
    int a = 0;
    int index = 0;
    for (byte b : bytes) {
        if (b < 0) {
            a = 256 + b;
        } else {
            a = b;
        }

        buf[index++] = HEX_CHAR[a / 16];
        buf[index++] = HEX_CHAR[a % 16];
    }

    return new String(buf);
}

输出为:00002710

//c++平台下
int i = 10000;
char c[10];
memcpy(c,&i,sizeof(i));

查看内存,排序为10270000

  • 定义一个byte数组 {0x01,0x00,0x00,0x00},分别查看不同平台下转为int时的值
//Java平台下:
byte [] b = {0x01,0x00,0x00,0x00};
int i = byteArrayToInt(b);
System.out.println(i+"");
//是以00000001 00000000 00000000 00000000 输出的i为16777216
//c++平台下:
char c[4] ={0x01,0x00,0x00,0x00};
int* p = (int*)c;//强转
int i=*p;
//是以00000000 00000000 00000000 00000001 输出的i为1 

工具方法:

//利用ByteBuffer查看字节序
int x = 10000;
ByteBuffer bb = ByteBuffer.wrap(new byte[4]);
bb.asIntBuffer().put(x);
String ss_before = Arrays.toString(bb.array());
System.out.println("默认字节序 " + bb.order().toString() + "," + " 内存数据 "+ ss_before);

bb.order(ByteOrder.LITTLE_ENDIAN);
bb.asIntBuffer().put(x);
String ss_after = Arrays.toString(bb.array());
System.out.println("修改字节序 " + bb.order().toString() + "," + " 内存数据 "+ ss_after);

int转byte数组

//将int转为按低端字节序排列的byte数组(c++内存存放顺序)
public static byte[] int2ByteArray(int res) {
    byte[] targets = new byte[4];
    targets[0] = (byte) (res & 0xff);
    targets[1] = (byte) ((res >> 8) & 0xff);
    targets[2] = (byte) ((res >> 16) & 0xff);
    targets[3] = (byte) (res >>> 24);
    return targets;
}
//将int转为高端字节序排列的byte数组(Java内存存放顺序)
public static byte[] int2ByteArray(int n) {
    byte[] byteArray = null;
    try {
        ByteArrayOutputStream byteOut = new ByteArrayOutputStream();
        DataOutputStream dataOut = new DataOutputStream(byteOut);
        dataOut.writeInt(n);
        byteArray = byteOut.toByteArray();
        Arrays.toString(byteArray);
    } catch (IOException e) {
        e.printStackTrace();
    }
    return byteArray;
}
//Java API 函数
public final void writeInt(int v) throws IOException {
        out.write((v >>> 24) & 0xFF);
        out.write((v >>> 16) & 0xFF);
        out.write((v >>>  8) & 0xFF);
        out.write((v >>>  0) & 0xFF);
        incCount(4);
    }

byte数组转int

//按低端字节序转int
public static int byteArray2Int(byte[] res) {         
    int targets = (res[0] & 0xff) | ((res[1] << 8) & 0xff00)| ((res[2] << 24) >>> 8) | (res[3] << 24);   
        return targets;   
    }
//按高端字节序转int
public static int byteArrayToInt(byte[] byteArray) {
    int n = 0;
    try {
        ByteArrayInputStream byteInput = new ByteArrayInputStream(byteArray);
        DataInputStream dataInput = new DataInputStream(byteInput);
        n = dataInput.readInt();
    } catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
    return n;
    }
//Java API 函数
public final int readInt() throws IOException {
        int ch1 = in.read();
        int ch2 = in.read();
        int ch3 = in.read();
        int ch4 = in.read();
        if ((ch1 | ch2 | ch3 | ch4) < 0)
            throw new EOFException();
        return ((ch1 << 24) + (ch2 << 16) + (ch3 << 8) + (ch4 << 0));
    }

API使用陷阱:

用OutputStream 的write(int)方法时要注意:

将指定的字节写入此输出流。write 的常规协定是:向输出流写入一个字节。

要写入的字节是参数 b 的八个低位。b 的 24 个高位将被忽略。

比如 传入int 1000,内存占位状态[0, 0, 39, 16],1000的八个低位即为16

你可能感兴趣的:(Java)