Java byte位移操作 注意事项

Java对byte 的 + - * / >> >>> << & | ^ (加,减,乘,除,右移,左移,无符号右移,位与,位或,位异或)操作,均会是首先将byte转化为int, 再行运算。这一事实可能导致多种问题:

 
 
假设我们想进行如下byte运算: 1111 1000 右移1位,再与0000 0001 或运算,得 0111 1101。
直觉写程序如下:
byte b = 0xf8;
byte b2 =  b >> 1 | 0x01;  
 
这个写法里有多重错误,现逐个纠正:
1 编译器报错,int无法直接自动转化为byte 
为解决此问题,加强制转化。
byte b = (byte)0xf8;
byte b2 = (byte)( (b >> 1) | 0x01);  
 
 
2 输出为 1111 1101 不是我们想要的 0011 1101
原因是>> 是有符号右移,当符号位为1时,左侧补的是1而非0。
修改为使用 >>> 无符号右移:
byte b = (byte)0xf8;
byte b2 = (byte)( (b >>> 1) | 0x01);  
 
3 运行后发现输出依然为 1111 1101 
原因是byte在运算前先转化为int再行位运算,因此分解后的运算步骤如下:
b 转化为int  1111 1000 转化为      11111111 11111111 11111111 11111000
无符号右移1位                      01111111 11111111 11111111 11111100
与 0x01 按位或                  01111111 11111111 11111111 11111101
强制转化回byte     11111101
解决方案,在右移运算前先 位与 0xff
byte b = (byte)0xf8;
byte b2 = (byte)( ((b & 0xff )>>> 1) | 0x01);  //注意必须加括号,因为 >>> 的优先级高于 &
 
 
4 运行后发现输出为我们想要的结果  0111 1101。运算步骤分解如下:
b 转化为int  1111 1000 转化为   11111111 11111111 11111111 11111000
和0xff 进行 & 操作              00000000 00000000 00000000 11111000
无符号右移1位   00000000 00000000 00000000 01111100
与 0x01 按位或  00000000 00000000 00000000 01111101
强制转化回byte  01111101
 
 
 
5 关于System.out.println();
byte b = (byte)0xf8;
System.out.println(b);   --最终输出为-8
运算步骤为:
b 转化为int  1111 1000 转化为   11111111 11111111 11111111 11111000
取符号位 -                      -1111111 11111111 11111111 11111000
取返+1(因为是按补码运算)      -0000000 00000000 00000000 00001000
输出  -8
 
 
 
 
 
最终结论:
1 区分使用 >> 和 >>>
2 在 >> 操作前要首先 & 0xff
3 注意符号优先级,正确使用括号。
4 需要强烈注意的一点是 & 的优先级小于 + . 因此 a = b & 0xff + 2000 的结果 可能不是你想要的
 
 
 
 
 
 
附:
打印byte,int 每个bit值的函数。
 
public static void printByte(byte b){
    for(int i = 7; i >=0 ; i --){
        int shiftleft = (b >> i) & 0x01;
        System.out.print(shiftleft);
    }
    System.out.println();
}
 
public static void printInt(int b){
    for(int i = 31; i >=0 ; i --){
        int shiftleft = (b >> i) & 0x01;
        System.out.print(shiftleft);
    }
    System.out.println();
}


如果您觉得阅读本文对您有帮助,请点一下“推荐”按钮,您的“推荐”将是我最大的写作动力!欢迎各位转载,但是未经作者本人同意,转载文章之后必须在文章页面明显位置给出作者和原文连接,否则保留追究法律责任的权利。
posted @   夜行过客  阅读(11242)  评论(0编辑  收藏  举报
编辑推荐:
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
阅读排行:
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
点击右上角即可分享
微信分享提示