TL;DR 使用b&6
,例如(byte)(11&6)
。请查看末尾的可工作的getBits()
实现。
首先,将11
强制转换为byte
没有什么意义,因为>>
运算符会将其强制转回一个int
值。
为了向您展示为什么您的代码不起作用,这里有一个显示所有中间步骤的程序:
public static void main(String[] args) {
for (byte i = 0; i <= 16; i++) {
int i1 = i >> 1;
int i2 = i1 << 6;
int i3 = i2 >> 5;
System.out.printf("%3d %s -> %3d %s -> %3d %10s -> %3d %s%n", i, bin(i), i1, bin(i1), i2, bin(i2), i3, bin(i3));
}
}
private static String bin(int value) {
String s = Integer.toBinaryString(value);
return "0000000".substring(Math.min(7, s.length() - 1)) + s;
}
输出:
0 00000000 -> 0 00000000 -> 0 00000000 -> 0 00000000
1 00000001 -> 0 00000000 -> 0 00000000 -> 0 00000000
2 00000010 -> 1 00000001 -> 64 01000000 -> 2 00000010
3 00000011 -> 1 00000001 -> 64 01000000 -> 2 00000010
4 00000100 -> 2 00000010 -> 128 10000000 -> 4 00000100
5 00000101 -> 2 00000010 -> 128 10000000 -> 4 00000100
6 00000110 -> 3 00000011 -> 192 11000000 -> 6 00000110
7 00000111 -> 3 00000011 -> 192 11000000 -> 6 00000110
8 00001000 -> 4 00000100 -> 256 100000000 -> 8 00001000
9 00001001 -> 4 00000100 -> 256 100000000 -> 8 00001000
10 00001010 -> 5 00000101 -> 320 101000000 -> 10 00001010
11 00001011 -> 5 00000101 -> 320 101000000 -> 10 00001010
12 00001100 -> 6 00000110 -> 384 110000000 -> 12 00001100
13 00001101 -> 6 00000110 -> 384 110000000 -> 12 00001100
14 00001110 -> 7 00000111 -> 448 111000000 -> 14 00001110
15 00001111 -> 7 00000111 -> 448 111000000 -> 14 00001110
16 00010000 -> 8 00001000 -> 512 1000000000 -> 16 00010000
您的高位未被清除,因为它正在处理 int
值。如果您将所有内容更改为 byte
,则会得到:
public static void main(String[] args) {
for (byte i = 0; i <= 16; i++) {
byte i1 = (byte)(i >> 1);
byte i2 = (byte)(i1 << 6);
byte i3 = (byte)(i2 >> 5);
System.out.printf("%3d %s -> %3d %s -> %4d %s -> %3d %s%n", i, bin(i), i1, bin(i1), i2, bin(i2), i3, bin(i3));
}
}
private static String bin(byte value) {
String s = Integer.toBinaryString(value & 0xFF);
return "0000000".substring(s.length() - 1) + s;
}
0 00000000 -> 0 00000000 -> 0 00000000 -> 0 00000000
1 00000001 -> 0 00000000 -> 0 00000000 -> 0 00000000
2 00000010 -> 1 00000001 -> 64 01000000 -> 2 00000010
3 00000011 -> 1 00000001 -> 64 01000000 -> 2 00000010
4 00000100 -> 2 00000010 -> -128 10000000 -> -4 11111100
5 00000101 -> 2 00000010 -> -128 10000000 -> -4 11111100
6 00000110 -> 3 00000011 -> -64 11000000 -> -2 11111110
7 00000111 -> 3 00000011 -> -64 11000000 -> -2 11111110
8 00001000 -> 4 00000100 -> 0 00000000 -> 0 00000000
9 00001001 -> 4 00000100 -> 0 00000000 -> 0 00000000
10 00001010 -> 5 00000101 -> 64 01000000 -> 2 00000010
11 00001011 -> 5 00000101 -> 64 01000000 -> 2 00000010
12 00001100 -> 6 00000110 -> -128 10000000 -> -4 11111100
13 00001101 -> 6 00000110 -> -128 10000000 -> -4 11111100
14 00001110 -> 7 00000111 -> -64 11000000 -> -2 11111110
15 00001111 -> 7 00000111 -> -64 11000000 -> -2 11111110
16 00010000 -> 8 00001000 -> 0 00000000 -> 0 00000000
问题在于使用>>
时会出现符号扩展。即使切换到>>>
也不起作用,因为>>>
在移位之前仍将其强制转换为带符号的int
。
要消除符号扩展,必须使用b & 0xFF
将byte
转换为int
,因为&
会将b
强制转换为带符号的int
,然后按位与运算符将删除所有这些位。
当然,如果您无论如何都要使用按位与运算符,请使用它来获得所需的结果,即b & 0b00000110
(或b & 6
)。
由于上述原因,getBits()
方法无法正常工作。
解决方案仍然是使用按位与运算符,但是从提供的from
和to
值构造位掩码。
这里的诀窍是使用(1<<x)-1
创建x
位的掩码,例如:5
-> 0b00011111
。因此,如果您想从2到4(包括2和4)构建0x00011111
(5位)和0x00000011
(2位),然后将它们异或以获取0x00011100
。
public static byte getBits(byte b, int from, int to) {
if (from < 0 || from > to || to > 7)
throw new IllegalArgumentException();
int mask = ((1 << (to + 1)) - 1) ^ ((1 << from) - 1);
return (byte)(b & mask);
}
0 00000000 -> 0 00000000
1 00000001 -> 0 00000000
2 00000010 -> 2 00000010
3 00000011 -> 2 00000010
4 00000100 -> 4 00000100
5 00000101 -> 4 00000100
6 00000110 -> 6 00000110
7 00000111 -> 6 00000110
8 00001000 -> 0 00000000
9 00001001 -> 0 00000000
10 00001010 -> 2 00000010
11 00001011 -> 2 00000010
12 00001100 -> 4 00000100
13 00001101 -> 4 00000100
14 00001110 -> 6 00000110
15 00001111 -> 6 00000110
16 00010000 -> 0 00000000
对于其他原始类型,请重载该方法:
public static byte getBits(byte value, int from, int to) {
if (from < 0 || from > to || to > 7)
throw new IllegalArgumentException();
int mask = ((1 << (to + 1)) - 1) ^ ((1 << from) - 1);
return (byte)(value & mask);
}
public static short getBits(short value, int from, int to) {
if (from < 0 || from > to || to > 15)
throw new IllegalArgumentException();
int mask = ((1 << (to + 1)) - 1) ^ ((1 << from) - 1);
return (short)(value & mask);
}
public static int getBits(int value, int from, int to) {
if (from < 0 || from > to || to > 31)
throw new IllegalArgumentException();
int mask = ((1 << (to + 1)) - 1) ^ ((1 << from) - 1);
return value & mask;
}
public static long getBits(long value, int from, int to) {
if (from < 0 || from > to || to > 63)
throw new IllegalArgumentException();
long mask = ((1L << (to + 1)) - 1) ^ ((1L << from) - 1);
return value & mask;
}
0b11 & 0x06
- infixed