java - BigInteger、BitSet 及其位和字节顺序

标签 java endianness

考虑以下代码(java8):

@Test
public void testBigIntegerVsBitSet() throws Throwable
{
    String bitString529 = "00000010 00010001";        // <- value = 529 (LittleEndian)
    byte[] arr529 = new byte[] { 0x02, 0x11 };        // <- the same as byte array (LittleEndian)
    BigInteger bigIntByString = new BigInteger( bitString529.replace( " ", ""), 2); // throws if there is a blank!
    BigInteger bigIntByArr = new BigInteger( arr529);
    BitSet bitsetByArr = BitSet.valueOf( arr529);  // interpretes bit-order as LittleEndian, but byte-order as BigEndian !!!

    System.out.println( "bitString529     : " + bitString529);              // bitString529     : 00000010 00010001
    System.out.println( "arr529.toString  : " + Arrays.toString( arr529));  // arr529.toString  : [2, 17]
    System.out.println( "bigIntByString   : " + bigIntByString);            // bigIntByString   : 529
    System.out.println( "bigIntByArr      : " + bigIntByArr);               // bigIntByArr      : 529
    System.out.println( "bitsetByArr      : " + bitsetByArr.toString() );   // bitsetByArr      : {1, 8, 12}
    System.out.println( "expecting        : {0, 4, 9}");                    // expecting        : {0, 4, 9}

    String bigIntByStringStr = toBitString( bigIntByString::testBit);
    String bigIntByArrStr = toBitString( bigIntByArr::testBit);
    String bitsetByArrStr = toBitString( bitsetByArr::get);

    System.out.println( "bigIntByStringStr: " + bigIntByStringStr);         // bigIntByStringStr: 1000100001000000
    System.out.println( "bigIntByArrStr   : " + bigIntByArrStr);            // bigIntByArrStr   : 1000100001000000
    System.out.println( "bitsetByArrStr   : " + bitsetByArrStr );           // bitsetByArrStr   : 0100000010001000
}

private String toBitString( Function<Integer, Boolean> aBitTester)
{
    StringBuilder sb =  new StringBuilder();
    for ( int i = 0; i < 16; i++ )
    {
        sb.append( aBitTester.apply( i) ? "1" : "0");
    }
    return sb.toString();
}

这证明 BitSet 将字节数组解析为 BIG_ENDIAN,而将(单个字节的)位顺序解释为 LITTLE_ENDIAN。相反,BigInteger 以 LITTLE_ENDIAN 解释两者,即使是通过位字符串加载时也是如此。

特别是两个类的位索引(BitInteger::testBit 与 BitSet::get)的迭代会产生不同的结果。

造成这种不一致的原因是什么?

最佳答案

Endianess 主要指字节的顺序,而不是各个位的顺序。后者与大多数应用程序无关,因为您无法对内存中的各个位进行寻址。因此,字节中位的字节顺序仅在重要的情况下使用,例如串行数据总线,否则字节通常被视为它们表示的没有任何字节顺序的数字( cf. WikipediaCan endianness refer to bits order in a byte? 的答案)。

因此,BitSet 将字节视为首先具有最低有效位,这样当您给它字节 0x01 时,您会得到具有最低有效位的预期结果位设置,无论它使用什么字节顺序来排序。这就是为什么使用 BigIntegerBitSet 的输出仅在字节顺序上有所不同。

请注意,对于字节顺序,BitSet 使用小字节序,而 BigInteger 使用大字节序(与您声称的不同)。

至于为什么BitSet使用与BigInteger不同的字节序,我们只能推测。请注意,受人尊敬的 BitSet 方法要新得多(仅在 Java 1.7 中引入),因此自从引入 BigInteger 以来,小端与大端顺序的重要性可能已经发生了变化.

关于java - BigInteger、BitSet 及其位和字节顺序,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43171915/

相关文章:

java - 圆圈之间的掠视碰撞

c - 了解两种字节顺序

c - 位 vector 运算和字节顺序

JavaScript 将小端字符串转换为数字

java - 从字节数组转换为短数组会产生错误的负值

powershell - 在 PowerShell 中反转字节顺序

java - 如何在java中将千分之一或更低的字符串格式化为日期?

java - Netbeans 有用的键盘快捷键

java - 如何从文件中只读取整数?

java - 没有从字符串值 ('' 反序列化的字符串参数构造函数/工厂方法)