We are using Java ByteBuffer for socket communication with a C++ server. We know Java is Big-endian and Socket communication is also Big-endian. So whenever the byte stream received and put into a ByteBuffer by Java, we call getInt() to get the value. No problem, no conversion.
But if somehow we specifically set the ByteBuffer byte order to Little-endian (my co-worker actually did this),
will the Java automatically convert the Big-endian into the Little-endian when the data is put into the ByteBuffer?
Then the getInt() of the Little-endian version will return a right value to you?
I guess the answer to above two questions are yes. But when I try to verify my guessing and try to find how the getInt() works in ByteBuffer, I found it is an abstract method. The only subclass of ByteBuffer is the MappedByteBuffer class which didn't implement the abstract getInt(). So where is the implementation of the getInt() method?
For the sending, because we are using Little-endian ByteBuffer, we need to convert them into a Big-endian bytes before we put onto the socket.
ByteBuffer will automatically use the byte order you specify. (Or Big endian by default)
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());
Both direct and heap ByteBuffers will re-order bytes as you specifiy.
So where is the implementation of the getInt() method?
ByteBuffer is indeed an abstract class. There are several way in which byte buffers can be created:
allocate
;wrap
;allocateDirect
.In my JDK, these create instances of internal classes HeapByteBuffer
and DirectByteBuffer
. Their respective getInt
functions are as follows:
// 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);
}
and
// 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))));
}
In the above, nativeByteOrder
and bigEndian
are two boolean members indicating respectively -- and somewhat redundantly -- whether the configured byte order: (a) matches the native byte order; (b) is big endian.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With