java中的大端和小端存儲


前言

  • 字節序:
    指多字節數據在計算機內存中存儲或者網絡傳輸時各字節的存儲順序,有大端和小端兩種方式
  • 大端:
    指高位字節存放在內存的低地址端,低位字節存放在內存的高地址端。
  • 小端:
    指低位字節放在內存的低地址端,高位字節放在內存的高地址端。

以一個int值 0x01020304 為例

存儲方式和CPU架構有關,IA架構(Intel、AMD)的CPU中是Little-Endian,而PowerPC 、SPARC和Motorola是Big-Endian

獲取CPU使用的存儲方式

在windows下

import java.nio.ByteOrder;

public class Client {

  public static void main(String[] args) {
    System.out.println(ByteOrder.nativeOrder());
  }
}

輸出為

LITTLE_ENDIAN

java8中的實現原理為

public static ByteOrder nativeOrder() {
        return Bits.byteOrder();
    }
static ByteOrder byteOrder() {
        if (byteOrder == null)
            throw new Error("Unknown byte order");
        return byteOrder;
    }

    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);
        }
    }

java11中實現原理為

public static ByteOrder nativeOrder() {
        return NATIVE_ORDER;
    }
private static final ByteOrder NATIVE_ORDER
        = Unsafe.getUnsafe().isBigEndian()
            ? ByteOrder.BIG_ENDIAN : ByteOrder.LITTLE_ENDIAN;
public final boolean isBigEndian() { return BE; }
private static final boolean BE = theUnsafe.isBigEndian0();
private native boolean isBigEndian0();

修改java中的存儲方式

java中默認使用大端

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

public class Client {

  public static void main(String[] args) {
    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]

源碼實現為

public IntBuffer asIntBuffer() {
        int size = this.remaining() >> 2;
        long addr = address + position();
        return (bigEndian
                ? (IntBuffer)(new ByteBufferAsIntBufferB(this,
                                                             -1,
                                                             0,
                                                             size,
                                                             size,
                                                             addr))
                : (IntBuffer)(new ByteBufferAsIntBufferL(this,
                                                             -1,
                                                             0,
                                                             size,
                                                             size,
                                                             addr)));
    }
public IntBuffer put(int x) {

        int y = (x);
        UNSAFE.putIntUnaligned(bb.hb, byteOffset(nextPutIndex()), y,
            true);
        return this;
    }
/** @see #putLongUnaligned(Object, long, long, boolean) */
    public final void putIntUnaligned(Object o, long offset, int x, boolean bigEndian) {
        putIntUnaligned(o, offset, convEndian(bigEndian, x));
    }

核心在於

private static int convEndian(boolean big, int n)     { return big == BE ? n : Integer.reverseBytes(n)  ; }

參考

Java中的大端和小端
java字節序、主機字節序和網絡字節序掃盲貼
java內存,大端小端判斷


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM