根据文章here,在处理负数时,ByteBuffers上的compareTo方法可能无法正常工作
bytes in Java are signed, contrary to what one typically expects. What is easy to miss
though, is the fact that this affects ByteBuffer.compareTo() as well. The Java API
documentation for that method reads:
"Two byte buffers are compared by comparing their sequences of remaining elements
lexicographically, without regard to the starting position of each sequence within its
corresponding buffer."
A quick reading might lead one to believe the result is what you would typically expect,
but of course given the definition of a byte in Java, this is not the case. The result
is that the order of byte buffers that contains values with the highest order bit set,
will diverge from what you may be expecting.
我尝试了几个将负值放入缓冲区的例子,并与积极因素进行比较,总是没问题。例如,当我们谈到这种情况时读取二进制数据,当整数-1
存储为100000...001
并且会导致问题?
答案 0 :(得分:0)
作为问题下方的 mentioned in the comments,public int compareTo(ByteBuffer that)
的描述:
...
通过按字典顺序比较剩余元素的序列来比较两个字节缓冲区,而不考虑每个序列在其相应缓冲区中的起始位置。像通过调用 Byte.compare(byte,byte)
一样比较字节元素对。
...
导致public int compareTo(Byte anotherByte)
...
返回值 0
如果此 Byte
等于参数 Byte
;如果此 0
在数值上小于参数 Byte
,则为小于 Byte
的值;如果此 0
在数值上大于参数 Byte
(有符号比较[强调我的]),则该值大于 Byte
。
...
因此在 JavaDoc 描述中,区分非常清楚。实际上,大多数高级 Java 开发人员都会预料到这里会出现问题,并且会理解 compareTo
中发生的情况。所以从这个意义上说,没有混淆。
这使 this other answer 无效,因为 Java 中没有实现差异的余地。
问题当然是在大多数其他编程语言中,字节被视为无符号。此外,字节数组的字典序比较通常会假设字节是无符号的(较大的结构/数字不太可能由可能具有负值的无符号字节创建)。
因此,习惯了其他语言的毫无戒心的程序员,或者只是盲目地假设无符号字节(并将描述中的“比较字节”直接翻译为 ByteBuffer.compareTo(ByteBuffer that)
)的程序员会感到惊讶。
这第二部分是文章所暗指的。处理字节在 Java 中可以说是一个错误,因为您通常使用这些构造不是为了节省内存,而是为了 IO,并且通常将字节视为无符号。
答案 1 :(得分:-1)
该文章声称,包含高位设置的ByteBuffer
字节(即,值范围为0x80
到0xFF
的字节)将被视为负数与另一个缓冲区中的相应字节进行比较时的值。换句话说,每个字节被视为8位有符号整数。因此,您应该期望0x90
的字节值将小于的字节值0x30
。
至少,这是理论,考虑到Java中byte
值的标准行为。在实践中,我希望将字节作为8位无符号整数进行比较,以便0x90
的字节比较大于一个字节{ {1}}。
这完全取决于如何解释术语“词典顺序”。例如,如果每个字节代表一个8位字符代码,那么它应该在逻辑上被视为无符号值(无论Java通常如何处理0x30
个对象)。
因此,归结为如何实际实现两个byte
的比较。一种方法是将字节视为Java签名整数,如:
ByteBuffers
另一种方法是将字节视为无符号整数,它使用略微不同的算术进行比较:
// Note: Code has be simplified for brevity
int compare(byte[] buf1, byte[] buf2)
{
...
for (int i = 0; i < buf1.length && i < buf2.length; i++)
{
int cmp = buf1[i] - buf2[i]; // Signed arithmetic
if (cmp != 0)
return cmp;
}
return (buf1.length - buf2.length);
}
正如我上面所说,我希望第二种方法可以被大多数实现使用,而不会给出“词典顺序”的任何具体定义。