我有以下方法:
int convert3ByteChunkTo24Bits(final byte[] bytes) {
int bitsFor3ByteChunk = 0;
bitsFor3ByteChunk = bitsFor3ByteChunk | (bytes[0] & 0b11111111);
bitsFor3ByteChunk = bitsFor3ByteChunk << 8;
bitsFor3ByteChunk = bitsFor3ByteChunk | (bytes[1] & 0b11111111);
bitsFor3ByteChunk = bitsFor3ByteChunk << 8;
bitsFor3ByteChunk = bitsFor3ByteChunk | (bytes[2] & 0b11111111);
return bitsFor3ByteChunk & 0b00000000_11111111_11111111_11111111;
}
该方法的目的是追加传递的字节并以int格式返回。这是我的测试方法:
void testConvert3ByteChunkTo24Bits() {
final byte ca = (byte) 0xCA;
final byte fe = (byte) 0xFE;
final byte ba = (byte) 0xBA;
final byte[] man = {ca, fe, ba};
final int bytesIn24Bits = base64EncoderHelper.convert3ByteChunkTo24Bits(man);
System.out.println(bytesIn24Bits);
}
结果输出为:
13303482
以二进制形式表示:
00000000110010101111111010111010
这是正确的,是以后的预期结果:
0xCA = 11001010
0xFE = 11111110
0xBA = 10111010
所以,到目前为止一切顺利。只有一件事我不明白,为什么我需要逻辑和
(bytes[0] & 0b11111111)
当我不进行按位和操作时,如果实现如下:
int convert3ByteChunkTo24Bits(final byte[] bytes) {
int bitsFor3ByteChunk = 0;
bitsFor3ByteChunk = bitsFor3ByteChunk | (bytes[0]);
bitsFor3ByteChunk = bitsFor3ByteChunk << 8;
bitsFor3ByteChunk = bitsFor3ByteChunk | (bytes[1]);
bitsFor3ByteChunk = bitsFor3ByteChunk << 8;
bitsFor3ByteChunk = bitsFor3ByteChunk | (bytes[2]);
return bitsFor3ByteChunk & 0b00000000_11111111_11111111_11111111;
}
结果将是:
00000000111111111111111110111010
我错过了什么?什么
bytes[0] & 0b11111111
修复此处? (我发现它有点试用 - 错误,但仍然好奇为什么它有效..)
答案 0 :(得分:1)
它处理有符号字节。
说byte[0]
的值为0b10000000。这看起来对你和我来说都是128,但由于manual,它看起来像-128
。在使用int的计算中使用该值时,它将被符号扩展为值为11111111111111111111111110000000
的int,这是一个值为-128
的int
为避免此问题,此代码按位0b11111111
执行。这是一个整数运算,因此该字节隐式转换为int 11111111111111111111111110000000
,但and
将其转换为00000000000000000000000010000000
,这是所需的128。
这是对two's complement arithmatic的臭名昭着的Java问题的攻击。</ p>
答案 1 :(得分:1)
在:
bitsFor3ByteChunk = bitsFor3ByteChunk | (bytes[0] & 0b11111111);
bytes[0]
首先扩展为int
值(整数全部用两个补码表示)。然后,对于存储在0xFF
中的byte
这样的值,相应的int
值将为0xFFFFFFFF
。然后屏蔽它以保留低8位。
答案 2 :(得分:0)
人类可读的等价物只是
Byte.toUnsignedInt(b)
或者如果你真的想明确但效率低下:
b < 0? b + 256: b
老实说,当jdk方法或简单数学存在同样的事情时编写类似的代码只是混淆,我希望编写这样的代码的人永远不会和其他人一起结束......除非他们在C语言或其他一些固有的低级别字节争论项目中编写设备驱动程序。