8

我们使用 Java ByteBuffer 与 C++ 服务器进行套接字通信。我们知道 Java 是 Big-endian,而 Socket 通信也是 Big-endian。所以每当Java接收到字节流并将其放入ByteBuffer中时,我们都会调用getInt()来获取值。没问题,没有转换。

但是如果我们以某种方式专门将 ByteBuffer 字节顺序设置为 Little-endian(我的同事实际上是这样做的),

  1. 当数据放入ByteBuffer时,Java会自动将Big-endian转换为Little-endian吗?

  2. 那么 Little-endian 版本的 getInt() 会返回一个正确的值给你吗?

我想以上两个问题的答案都是肯定的。但是当我尝试验证我的猜测并尝试找出 getInt() 在 ByteBuffer 中的工作原理时,我发现它是一个抽象方法。ByteBuffer 的唯一子类是 MappedByteBuffer 类,它没有实现抽象 getInt()。那么getInt()方法的实现在哪里呢?

对于发送,因为我们使用的是 Little-endian ByteBuffer,所以我们需要将它们转换为 Big-endian 字节,然后才能放入套接字。

4

2 回答 2

9

ByteBuffer 将自动使用您指定的字节顺序。(或默认为大端)

 ByteBuffer bb =
 // to use big endian
 bb.order(ByteOrder.BIG_ENDIAN);

 // to use little endian
 bb.order(ByteOrder.LITTLE_ENDIAN);

 // use the natural order of the system.
 bb.order(ByteOrder.nativeOrder()); 

直接和堆 ByteBuffers 都将根据您的指定重新排序字节。

于 2011-08-04T15:27:29.880 回答
3

那么getInt()方法的实现在哪里呢?

ByteBuffer确实是一个抽象类。有几种方法可以创建字节缓冲区:

在我的 JDK 中,这些创建内部类的实例HeapByteBufferDirectByteBuffer. 它们各自的getInt功能如下:

// HeapByteBuffer

public int getInt() {
    return Bits.getInt(this, ix(nextGetIndex(4)), bigEndian);
}

public int getInt(int i) {
    return Bits.getInt(this, ix(checkIndex(i, 4)), bigEndian);
}

// DirectByteBuffer

private int getInt(long a) {
    if (unaligned) {
        int x = unsafe.getInt(a);
        return (nativeByteOrder ? x : Bits.swap(x));
    }
    return Bits.getInt(a, bigEndian);
}

public int getInt() {
    return getInt(ix(nextGetIndex((1 << 2))));
}

public int getInt(int i) {
    return getInt(ix(checkIndex(i, (1 << 2))));
}

在上面,nativeByteOrderbigEndian是两个布尔成员,分别表示 - 并且有点多余 - 配置的字节顺序是否:(a)与本机字节顺序匹配;(b) 是大端。

于 2011-08-04T15:29:22.913 回答