Java默认大端,但协议可能用小端;需显式调用order(ByteOrder.LITTLE_ENDIAN)设置字节序,且必须在getInt等操作前设置;解析时应避免直接使用array(),而要用get(data)安全拷贝有效字节。

Java 默认大端,但协议可能用小端
Java 的 ByteBuffer、DataInputStream 等默认按大端(Big-Endian)解析整数,而很多嵌入式设备、C/C++ 服务端或硬件协议(如 Modbus、某些传感器帧)习惯用小端(Little-Endian)。如果你直接用 buffer.getInt() 解析小端数据,结果会完全错乱——比如本该是 0x01000000(十进制 16777216),却读成 0x00000001(1)。
关键不是“Java 不支持小端”,而是你必须显式声明。不设,默认就是大端;设了,才生效。
-
ByteBuffer.order(ByteOrder.LITTLE_ENDIAN)必须在调用getInt()、getShort()等方法前设置,且对后续所有读写操作生效 - 同一个
ByteBuffer实例不能混用大小端读取——比如先设小端读int,再临时切大端读float,不行;得用两个 buffer 或手动位移拼接 - WebSocket、Netty、自定义 TCP 拆包中收到的
ByteBuffer,其order()是初始值(通常是BIG_ENDIAN),不会自动适配远端字节序
解析时别依赖 buffer.array() 直接强转
很多人图省事,拿到 ByteBuffer message 后直接写 byte[] data = message.array(),再用 ByteBuffer.wrap(data).order(...) ——这会出问题。因为 array() 返回的是底层数组全量引用,不考虑 position 和 limit,很可能读到脏数据或越界。
正确做法永远是先提取有效区间:
立即学习“Java免费学习笔记(深入)”;
- 用
message.remaining()获取当前可读字节数 - 分配新数组:
byte[] data = new byte[message.remaining()] - 用
message.get(data)安全拷贝,再 wrap 这个干净的data - 如果要复用 buffer(如 Netty 的
ByteBuf),记得调用readableBytes()+getBytes(...),而不是碰array()
处理混合字节序字段要手动位移拼接
有些协议头是大端,正文 payload 是小端;或者一个字段里高位字节是大端,低位又嵌套小端标志位。这时靠 order() 切换不够用,必须手拆字节。
例如:某协议规定第 5–8 字节为小端 uint32,但第 4 字节的 bit7 和 bit6 是两个独立开关位(bit7=0x80, bit6=0x40),且这字节本身属于大端上下文:
- 先用大端 buffer 读前 4 字节(含开关位):
buffer.order(BIG_ENDIAN).getShort(); ... - 单独取第 4 字节:
byte flagByte = data[3],再用(flagByte & 0x80) == 0x80判断开关 - 对第 5–8 字节,手动组合小端 int:
((data[7] & 0xFF) - 注意:这里下标是按原始字节数组顺序写的,
data[4]是第 5 字节,对应小端的最低字节
容易被忽略的 signed/unsigned 类型陷阱
Java 没有无符号基础类型,byte、short、int 全是有符号的。但协议里常出现 uint8、uint16、uint32。直接用 buffer.get() 得到的 byte 是 -128~127,而你想要 0~255。
常见错误写法:int value = buffer.get(); → 若原始是 0xFF,得到 -1,不是 255。
正确做法统一加 & 0xFF(对 byte)或 & 0xFFFF(对 short):
int uint8 = buffer.get() & 0xFF;-
int uint16 = buffer.getShort() & 0xFFFF;(注意:getShort()仍受order()影响) - uint32 用
getInt()即可,因int范围覆盖 0~4294967295,但若协议明确要求无符号语义,后续比较或运算仍需小心溢出
最麻烦的是 uint64:Java long 是有符号的,最大正数是 9223372036854775807,而 uint64 最大是 18446744073709551615。超出部分只能用 BigInteger 或拆成两个 int 存,不能硬 cast。


















