Java BitSet 错误转换 from/to 字节数组
Java BitSet wrong conversion from/to byte array
使用 BitSets 我有一个失败的测试:
BitSet bitSet = new BitSet();
bitSet.set(1);
bitSet.set(100);
logger.info("BitSet: " + BitSetHelper.toString(bitSet));
BitSet fromByteArray = BitSetHelper.fromByteArray(bitSet.toByteArray());
logger.info("fromByteArray: " + BitSetHelper.toString(bitSet));
Assert.assertEquals(2, fromByteArray.cardinality());
Assert.assertTrue(fromByteArray.get(1)); <--Assertion fail!!!
Assert.assertTrue(fromByteArray.get(100)); <--Assertion fail!!!
更奇怪的是,我可以看到两个 BitSet 的字符串表示形式:
17:34:39.194 [main] INFO c.i.uniques.helper.BitSetHelperTest - BitSet: 00000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000
17:34:39.220 [main] INFO c.i.uniques.helper.BitSetHelperTest - fromByteArray: 00000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000
是平等的!这里发生了什么??
本例中使用的方法有:
public static BitSet fromByteArray(byte[] bytes) {
BitSet bits = new BitSet();
for (int i = 0; i < bytes.length * 8; i++) {
if ((bytes[bytes.length - i / 8 - 1] & (1 << (i % 8))) > 0) {
bits.set(i);
}
}
return bits;
}
以及用于获取字符串表示的方法:
public static String toString(BitSet bitSet) {
StringBuffer buffer = new StringBuffer();
for (byte b : bitSet.toByteArray()) {
buffer.append(String.format("%8s", Integer.toBinaryString(b & 0xFF)).replace(' ', '0'));
}
return buffer.toString();
}
有人能解释一下这是怎么回事吗?
请注意 BitSet
有一个 valueOf(byte[])
已经为您执行此操作。
在你的fromByteArray
方法中
for (int i = 0; i < bytes.length * 8; i++) {
if ((bytes[bytes.length - i / 8 - 1] & (1 << (i % 8))) > 0) {
bits.set(i);
}
}
您正在反向遍历 byte[]
。在第一次迭代中,
bytes.length - i / 8 - 1
将评估为
8 - (0 / 8) - 1
即7
,它将访问最高有效字节。这是包含原始位集中第 100 位的位。从反面看,这是第四位。如果您检查生成的 BitSet
中设置的位,您会注意到第 5 位和第 98 位(此处可能存在一个错误)位已设置。
但是toByteArray()
返回的byte[]
包含
a little-endian representation of all the bits in this bit set
您需要按适当的顺序阅读byte[]
for (int i = 0; i < bytes.length * 8; i++) {
if ((bytes[i / 8] & (1 << (i % 8))) > 0) {
bits.set(i);
}
}
使用 BitSets 我有一个失败的测试:
BitSet bitSet = new BitSet();
bitSet.set(1);
bitSet.set(100);
logger.info("BitSet: " + BitSetHelper.toString(bitSet));
BitSet fromByteArray = BitSetHelper.fromByteArray(bitSet.toByteArray());
logger.info("fromByteArray: " + BitSetHelper.toString(bitSet));
Assert.assertEquals(2, fromByteArray.cardinality());
Assert.assertTrue(fromByteArray.get(1)); <--Assertion fail!!!
Assert.assertTrue(fromByteArray.get(100)); <--Assertion fail!!!
更奇怪的是,我可以看到两个 BitSet 的字符串表示形式:
17:34:39.194 [main] INFO c.i.uniques.helper.BitSetHelperTest - BitSet: 00000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000
17:34:39.220 [main] INFO c.i.uniques.helper.BitSetHelperTest - fromByteArray: 00000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000
是平等的!这里发生了什么??
本例中使用的方法有:
public static BitSet fromByteArray(byte[] bytes) {
BitSet bits = new BitSet();
for (int i = 0; i < bytes.length * 8; i++) {
if ((bytes[bytes.length - i / 8 - 1] & (1 << (i % 8))) > 0) {
bits.set(i);
}
}
return bits;
}
以及用于获取字符串表示的方法:
public static String toString(BitSet bitSet) {
StringBuffer buffer = new StringBuffer();
for (byte b : bitSet.toByteArray()) {
buffer.append(String.format("%8s", Integer.toBinaryString(b & 0xFF)).replace(' ', '0'));
}
return buffer.toString();
}
有人能解释一下这是怎么回事吗?
请注意 BitSet
有一个 valueOf(byte[])
已经为您执行此操作。
在你的fromByteArray
方法中
for (int i = 0; i < bytes.length * 8; i++) {
if ((bytes[bytes.length - i / 8 - 1] & (1 << (i % 8))) > 0) {
bits.set(i);
}
}
您正在反向遍历 byte[]
。在第一次迭代中,
bytes.length - i / 8 - 1
将评估为
8 - (0 / 8) - 1
即7
,它将访问最高有效字节。这是包含原始位集中第 100 位的位。从反面看,这是第四位。如果您检查生成的 BitSet
中设置的位,您会注意到第 5 位和第 98 位(此处可能存在一个错误)位已设置。
但是toByteArray()
返回的byte[]
包含
a little-endian representation of all the bits in this bit set
您需要按适当的顺序阅读byte[]
for (int i = 0; i < bytes.length * 8; i++) {
if ((bytes[i / 8] & (1 << (i % 8))) > 0) {
bits.set(i);
}
}