【数据结构】- Java字节序、主机字节序和网络字节序扫盲贴

  Java程序员是幸福,因为相对于C/C++的不跨平台,JVM为我们屏蔽了大量的底层细节和复杂性,让我们能够将精力放在实现特定的业务逻辑上,所以使用java开发项目效率是比较高的。同时java程序员是悲哀的,就是因为JVM屏蔽了很多技术细节,导致java程序员基本功普遍较差,对一些基本概念理解不深,甚至根本没有听说过。作为一个java程序员,我深深的感到自己知识面的狭窄。无意中看到了字节序,以前竟然都不知道,这里记录下,扫个盲。

       使用C/C++进行网络编程的程序员,肯定会接触到“字节序”的概念,但是使用java进行网络编程,却根本不会接触到“字节序”。为什么会这样呢?我们先从字节序说起。字节顺序是指占用内存多于一个字节类型的数据在内存中的存放顺序,有小端、大端两种顺序。小端字节序(little endian):低字节数据存放在内存低地址处,高字节数据存放在内存高地址处;大端字节序(bigendian):高字节数据存放在低地址处,低字节数据存放在高地址处。

        Java中一个int型数据占用4个字节,假如有一个16进制的int数,int value = 0x01020304;采用不同的字节序,在内存中的存储情况见下图:

显然大字节序,是比较符合人类思维习惯的。

      至于计算机到底是BIG-ENDIAN、LITTLE-ENDIAN、跟CPU有关的,一种CPU不是BIG-ENDIAN就是LITTLE-ENDIAN。IA架构(Intel、AMD)的CPU中是Little-Endian,而PowerPC 、SPARC和Motorola处理器是Big-Endian。这其实就是所谓的主机字节序。而网络字节序是指数据在网络上传输时是大头还是小头的,在Internet的网络字节序是BIG-ENDIAN。所谓的JAVA字节序指的是在JAVA虚拟机中多字节类型数据的存放顺序,JAVA字节序也是BIG-ENDIAN。可见网络和JVM都采用的是大字节序,个人感觉就是因为这种字节序比较符合人类的习惯。由于JVM会根据底层的操作系统和CPU自动进行字节序的转换,所以我们使用java进行网络编程,几乎感觉不到字节序的存在。

      那么java里面,怎么判断你的计算机是大端存储、还是小端存储呢?JDK为我们提供一个类ByteOrder,通过以下代码就可以知道机器的字节序

System.out.println(ByteOrder.nativeOrder());

在java.nio包下提供了ByteOrder、ByteBuffer等于字节序相关的类,我们也可以改变JVM中默认的字节序。该例子来源于
http://blog.csdn.net/veryitman/article/details/6819017

代码如下:

 

复制代码
package net.aty.util;


import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.Arrays;

public class JVMEndianTest {

public static void main(String[] args) {

int x = 0x01020304;

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);
}
}
复制代码

 

执行结果如下:
默认字节序 BIG_ENDIAN, 内存数据 [1, 2, 3, 4]
修改字节序 LITTLE_ENDIAN, 内存数据 [4, 3, 2, 1]

附工具类

复制代码
class ToBytesUtils {
    public static byte[] intToBytes(int value) {
        byte[] result = new byte[4];
        result[0] = (byte)((value >> 24) & 0xFF);
        result[1] = (byte)((value >> 16) & 0xFF);
        result[2] = (byte)((value >> 8) & 0xFF);
        result[3] = (byte)(value & 0xFF);
        return result;
    }
}
复制代码

 

posted @   多搞学习少搞事情  阅读(984)  评论(0编辑  收藏  举报
编辑推荐:
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
阅读排行:
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· 提示词工程——AI应用必不可少的技术
· Open-Sora 2.0 重磅开源!
点击右上角即可分享
微信分享提示