BigInteger,BitSet及其位和字节顺序

时间:2017-04-02 18:21:32

标签: 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)会产生不同的结果。

这种不一致是否有原因?

1 个答案:

答案 0 :(得分:3)

Endianess主要指的是字节的排序,而不是单个位的排序。后者在大多数应用程序中都不相关,因为您无法例如处理内存中的各个位。因此,字节中的位的字节顺序仅用于重要的情况,例如串行数据总线,否则字节通常被视为它们所代表的数字而没有任何字节顺序(cf. Wikipedia和{{3的答案}})。

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

请注意,对于字节顺序,BitSet使用little-endianness,而BigInteger使用big endianness(与您声明的不同)。

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