在java中改变一个字节内的位

时间:2013-04-10 04:11:54

标签: java bit-manipulation

所以我理解如何更改一个字节内的单个位,我不确定为什么我的特定代码无效。

public static void setBit(byte[] input, int position, int value) {
    int byteLocation = position / 8;
    int bitLocation = position % 8;
    byte tempByte = input[byteLocation];

    if (value == 0) 
    tempByte = (byte) (tempByte & ~(1 << bitLocation));
    else
    tempByte = (byte) (tempByte | (1 << bitLocation));

    input[byteLocation] = tempByte;
}

现在我用字符串“Testing1”(64位长)测试它,然后尝试设置位并显示值。它最多可以处理46位,然后在第47位,如果我尝试将其设置为1,它会自动运行,但是可以正常工作。

无法以我的方式看到错误,这是我测试它的方式

String test = "Testing1";

byte[] bytes = test.getBytes();

for (int i = 0; i < bytes.length; i++)
    System.out.print(String.format("%8s", Integer.toBinaryString(bytes[i])).replace(' ', '0') + "[" + i + "] ");

setBit(bytes, 44, 1);
System.out.println();
for (int i = 0; i < bytes.length; i++)
    System.out.print(String.format("%8s", Integer.toBinaryString(bytes[i])).replace(' ', '0') + "[" + i + "] ");

以下是我尝试将第47位更改为1

时的输出
01010100[0] 01100101[1] 01110011[2] 01110100[3] 01101001[4] 01101110[5] 01100111[6] 00110001[7] 
01010100[0] 01100101[1] 01110011[2] 01110100[3] 01101001[4] 11111111111111111111111111101110[5] 01100111[6] 00110001[7] 

5 个答案:

答案 0 :(得分:3)

将格式更改为

Integer.toBinaryString(0xFF & bytes[i])
需要屏蔽

字节,因为它是符号扩展的,而不是零扩展的,为32位int

答案 1 :(得分:2)

问题是您在相关字节中设置符号位。所以,该字节现在具有负值。你调用Integer.toBinaryString(),它接受​​一个int作为它的参数,而不是一个字节。字节被提升为int,并且它正确地计算值:

11101110

到它的等价整数:

11111111111111111111111111101110

答案 2 :(得分:0)

我使用^(xor)

缩小了你的方法
public static void setBit(byte[] input, int position, int value) {
    int byteLocation = position / 8;
    int bitLocation = position % 8;
    input[byteLocation] = (byte) (input[byteLocation] ^ (byte) (1 << bitLocation));
}

答案 3 :(得分:0)

我没有太详细地看过它,但我认为一口咬的问题是它被扩展为一个int(因为它已经签名,1扩展为负int)。

只需取字符串的最后8个字符即可。

答案 4 :(得分:0)

我最近不得不这样做。
我设法通过(大量使用白板但是......)将原始位移到我想要替换的LSB的位置并使所有位包含我想要替换的MSB,1&#39;秒。
然后我想要我想要的位代替我要替换的位,向左移动我向右移动的相同数字,或者用原始移动结果,用XOR&#编辑&#39; 39;替换的面具。 (深吸一口气,我试着解释)

让我们说我有字节:
1111 1010 0001 1001

我想用0001替换半字节1010以产生:

1111 0001 0001 1001.

我为实现这一目标而进行的操作是:

1)向右移动8以产生:
0000 0000 1111 1010

2)OR掩码0xf(1111)产生:
0000 0000 1111 1111

3)用0000 0000 1111 1111替换0001以产生:
0000 0000 0000 0001

4)向左移动8以产生:
0000 0001 0000 0000

5)将掩码移动到LSB位置,将XOR移动到全字节

1111 1111 1111 1111
0000 1111 0000 0000
 ==================
1111 0000 1111 1111

6)和XOR&#39; ed,移动掩模与原件产生:

1111 0000 0001 1001
1111 0000 1111 1111
 ==================
1111 0000 0001 1001

7)或以上更换的结果:

1111 0000 0001 1001
0000 0001 0000 0000
 ==================
1111 0001 0001 1001&lt;&lt; 最终结果
 ==================


在java中,这导致函数:

public long overwriteBits(long overwrite, long with, long shift, long mask)
{
    return ((((overwrite >> shift) | mask) & with) << shift) | (overwrite & (~0 ^ (mask << shift)));
}

在哪里&#34;覆盖&#34;是原始数据,&#34;&#34;是你想要的位代替位置&#34; shift&#34;和掩码是一系列正位,具有相同的替换长度。

为了做到这一点,我打电话(在sudo中):
overwriteBits(1111 1010 00011001, 0001 ,8,1111)

我想提一下,上面的内容适用于替换任何原语中的位,不需要字节数组。例如更换11位,如下所示:

1101001010101101 1111 0101 101 001101
1010 1010 101

overwriteBits(1101001010101101 1111 0101 101 001101 1010 1010 101, 6 11111111111)
/> 1101001010101101 1111 0101 101 001101
1101001010101101 1010 1010 101 001101

overwriteBits(1789785421l,1365l,6,0x7FF)