java%4d,java - 检索一个数字 - 堆栈内存溢出

这篇博客讨论了在Java中进行位操作时遇到的问题,特别是当涉及到类型转换和位移操作时。作者通过示例代码展示了byte类型的位操作如何受到类型提升的影响,导致预期结果的丢失。为了解决这个问题,提出了使用按位AND运算符结合位掩码来正确提取字节中的特定位段。此外,还提供了通用的`getBits()`方法,用于从任何原始类型中提取指定范围的位。博客强调了理解位运算和类型转换在编程中的重要性。
摘要由CSDN通过智能技术生成

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 ,然后按位AND运算符将删除所有这些位。

当然,如果您打算使用按位AND,只需使用它来获得所需的结果,即b & 0b00000110 (或b & 6 )。

出于与上述相同的原因, getBits()方法不起作用。

解决方案仍然是使用按位AND运算符,但是从提供的from和to值构造位掩码。

这里的技巧是使用(1 << x) - 1来创建x位的掩码,例如5 - > 0b00011111 。 因此,如果您想要2到4(包括2和4),请构建0x00011111 (5!位)和0x00000011 (2位),然后将它们XOR以获得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;

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值