例如:数字0x12345678在内存中的表示形式为:
1. 大端序
0x12|0x34|0x56|0x78 低地址——>高地址
2. 小端序
0x78|0x56|0x34|0x12
内存地址 小端 大端
0x0001 0x78 0x12
0x0002 0x56 0x34
0x0003 0x34 0x56
0x0004 0x12 0x78
大端序是按照数字的书写顺序进行存储的,而小端序是颠倒书写顺序进行存储的。
在java.nio.ByteOrder类中有方法nativeOrder()可以判断JVM底层硬件CPU的大小端信息(本机字节顺序)。此方法的定义使得对性能敏感的Java代码能分配字节顺序与硬件相同的直接缓冲区。本机代码库通常在使用此类缓冲区时更为高效。
/*
* 测试本机字节顺序
*/
import java.nio.ByteOrder;
public class EndianTest {
public static void main(String[] args) throws IOException{
if(ByteOrder.nativeOrder() == ByteOrder.BIG_ENDIAN){
System.out.println("Big Endian");
}
else System.out.println("little Endian");
}
}
在Windows Intel上输出的结果是:little Endian。
现在主流的CPU,intel系列的是采用的little endian的格式存放数据,而motorola系列的CPU采用的是big endian,ARM则同时支持 big和little。
特别需要注意的是,C/C++语言编写的程序里数据存储顺序是跟编译平台所在的CPU相关的,而 JAVA编写的程序则唯一采用big endian方式来存储数据。所以JVM采用的其实是大端序。可以通过将整形转成字节数组,或者字节数组转成整形的方式进行判断。
//测试JVM字节序
import java.io.ByteArrayInputStream;
import java.io.DataInputStream;
import java.io.IOException;
public class EndianTest {
public static void testJvm() throws IOException
{
byte[] byteAr = new byte[]{0x78,0x56,0x34,0x12};
ByteArrayInputStream bais = new ByteArrayInputStream(byteAr);
DataInputStream dis = new DataInputStream(bais);
System.out.println(Integer.toHexString(dis.readInt()));
}
public static void main(String[] args) throws IOException{
testJvm();
}
}
输出结果是:78563412
可以说明它是大端序。
bool IsBigEndian()
{
int a =1 ;
if(((char*)&a)[3] ==1)
return true ;
else
return false ;
}
联合体union的存放顺序是所有成员都从低地址开始存放,利用该特性可以轻松地获得了CPU对内存采用Little-endian还是Big-endian模式读写:
bool IsBigEndian()
{
union
{
unsigned short a ;
char b ;
} c;
c.a =0x0102 ;
if(c.b ==1)
return true ;
else
return false ;
}
Union是一个特殊的结构,其中所有成员共享结一个内存地址,任意时间只能存储一个成员。
网络编程中,TCP/IP统一采用大端方式传送数据,所以有时我们也会把大端方式称之为网络字节序。当两台采用不同字节序的主机通信时,在发送数据之前都必须经过字节序的转换成为网络字节序(即大端方式)后再进行传输。此外用C/C++在小端方式的机器上编写的程序与java程序互通时也要进行大端和小端的转换。
这里所谓转换就是改变字节的排序,使交互时数据保持一致。举一个例子,还是16进制表示的数0x12345678,在小端机器上排序为0x78563412,当内存中这样的数传输时,在大端方式下就是0x78563412这个值,与原值不同,要想与原值相同,在传输前,在大端方式下就该是0x12345678,这时原数在内存中为0x12345678,即将原数据0x12345678在内存存储序列为0x12345678,也就是要转换成大端方式。
由于java采用的字节序同网络协议采用的字节序是一样的,它们都是选择的人们通常更容易理解的大端模式(big endian),所以java在接收网络数据是不需要像C/C++那样先调用ntohl和ntohs实现网络字节序与主机字节序的转换,java程序可以直接接收网络数据来进行处理。然而在与采用不同字节序的语言所编写的程序进行通信时,java程序中通常要进行数据类型的转换和解析。
转换的方法见:http://blog.csdn.net/wtbee/article/details/11297643