ByteBuffer - compareTo方法可能会分歧

时间:2014-03-07 15:55:42

标签: java nio bytebuffer compareto

根据文章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并且会导致问题?

2 个答案:

答案 0 :(得分:0)

作为问题下方的 mentioned in the commentspublic 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字节(即,值范围为0x800xFF的字节)将被视为负数与另一个缓冲区中的相应字节进行比较时的值。换句话说,每个字节被视为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);
}

正如我上面所说,我希望第二种方法可以被大多数实现使用,而不会给出“词典顺序”的任何具体定义。