Java整型的字节序是()
A.Little-Endian(小端)
B.Big-Endian(大端)
C.由运行程序的CPU决定
D.由编译程序的CPU决定
对于大小端,我估计肯定有很多开发人员跟我一样都没听过
由于Java是跨平台的,JVM为我们屏蔽了大量的底层细节和复杂性,导致在平时的时候根本不会接触到。以下是我通过大量咨询,查找整理的结果。
字节序:指多字节数据在计算机内存中存储或者网络传输时各字节的存储顺序,有大端
和小端
两种方式
大端:指高位字节存放在内存的低地址端,低位字节存放在内存的高地址端。十六进制整数0x01020304
在内存中存储方式,由于一个整型在内存中占4个字节,因此被划分成4份分别存储在连续的内存地址位中
小端:指低位字节放在内存的低地址端,高位字节放在内存的高地址端。同样0x01020304
在内存中的存储方式为
在计算机中既可以是大端
存储,也可以小端
存储,跟CPU架构有关,IA架构(Intel、AMD)的CPU中是Little-Endian,而PowerPC 、SPARC和Motorola处理器是Big-Endian
基于Java8
,在Java中提供了一个api可以获取CPU使用的字节序:
ByteOrder byteOrder = ByteOrder.nativeOrder(); //LITTLE_ENDIAN,CPU是Intel的 System.out.println(byteOrder);
通过查看ByteOrder.nativeOrder()
源码,其最后调用了Bits.byteOrder()
// -- Processor and memory-system properties -- private static final ByteOrder byteOrder; static ByteOrder byteOrder() { if (byteOrder == null) throw new Error("Unknown byte order"); return byteOrder; } /** * 通过返回0x01,还是0x08来判断CPU使用的是BIG_ENDIAN,还是LITTLE_ENDIAN **/ static { long a = unsafe.allocateMemory(8); try { unsafe.putLong(a, 0x0102030405060708L); byte b = unsafe.getByte(a); switch (b) { case 0x01: byteOrder = ByteOrder.BIG_ENDIAN; break; case 0x08: byteOrder = ByteOrder.LITTLE_ENDIAN; break; default: assert false; byteOrder = null; } } finally { unsafe.freeMemory(a); } }
对于Java,其实既有使用大端,也有使用小端,对于ByteBuffer,默认使用的Big-Endian(大端),也可以对默认方式进行修改,如下例子
int x = 0x01020304; ByteBuffer byteBuffer = ByteBuffer.wrap(new byte[4]); byteBuffer.asIntBuffer().put(x); String before = Arrays.toString(byteBuffer.array()); System.out.println("默认字节序:"+byteBuffer.order().toString() + "," + "内存数据:"+before); byteBuffer.order(ByteOrder.LITTLE_ENDIAN); byteBuffer.asIntBuffer().put(x); String after = Arrays.toString(byteBuffer.array()); System.out.println("修改字节序:"+byteBuffer.order().toString()+","+"内存数据:"+after);
默认字节序:BIG_ENDIAN,内存数据:[1, 2, 3, 4] 修改字节序:LITTLE_ENDIAN,内存数据:[4, 3, 2, 1]
通过查看ByteBuffer.wrap
,其声明了一个HeapByteBuffer
public static ByteBuffer wrap(byte[] array, int offset, int length) { try { return new HeapByteBuffer(array, offset, length); } catch (IllegalArgumentException x) { throw new IndexOutOfBoundsException(); } }
所以byteBuffer.asIntBuffer()
实际调用了HeapByteBuffer
中的方法
public IntBuffer asIntBuffer() { int size = this.remaining() >> 2; int off = offset + position(); return (bigEndian ? (IntBuffer)(new ByteBufferAsIntBufferB(this,-1,0,size,size,off)) : (IntBuffer)(new ByteBufferAsIntBufferL(this,-1,0,size,size,off))); }
bigEndian
表示是否是大端,默认为true,所以后面put的时候实际是往ByteBufferAsIntBufferB
大端中存储数据,但也可以调整为使用小端来存储数据,byteBuffer.order(ByteOrder.LITTLE_ENDIAN);
这题的答案是B,但实际却是Java中既能有大端也能有小端,只是Java默认使用了大端