Java位运算_java 30 位运算拆开-程序员宅基地

技术标签: 右移  与或非  编程语言  应用场景  左移  位运算  

在位运算前,需要先了解二进制码相关知识,详情请见博主的另一篇博文:原码、反码、补码


Java定义了位运算符,应用于整数类型(int),长整型(long),短整型(short),字符型(char),和字节类型(byte)等类型。

Java包含了七种位运算符

位运算符 说明
>> 右移运算符,符号左侧数值 按位右移 符号右侧数值指定的位数,若为正数则高位补0,若为负数则高位补1
<< 左移运算符,符号左侧数值 按位左移 符号右侧数值指定的位数,并在低位处补0
>>> 无符号右移运算符,符号左侧数值 按位右移 符号右侧数值指定的位数,无论正负高位补0
& (AND)运算符,对两个整型操作数中对应位执行布尔代数,两个位都为1时输出1,否则0
| (OR)运算符,对两个整型操作数中对应位执行布尔代数,两个位中只要有一个为1就输出1,否则为0
^ 异或(XOR)运算符,对两个整型操作数中对应位执行布尔代数,两个位相等则为0,不相等则为1
~ (NOT)运算符,按位取反运算符翻转操作数的每一位,即0变成1,1变成0

七种位运算示例代码

int a = -20;
int b = 30;
int result1 = a << 1;
int result2 = a >> 1;
int result3 = a >>> 1;
int result4 = a & b;
int result5 = a | b;
int result6 = a ^ b;
int result7 = ~ a;

运算结果如下

-40
-10
2147483638
12
-2
-14
19

原理解析如下(高位0为博主手动补齐,方便观看)

a = 11111111 11111111 11111111 11101100
b = 00000000 00000000 00000000 00011110
-----------------
a << 1	-->	11111111 11111111 11111111 11011000
a >> 1	-->	11111111 11111111 11111111 11110110
a >>> 1	-->	01111111 11111111 11111111 11110110	
a & b 	= 	00000000 00000000 00000000 00001100
a | b 	= 	11111111 11111111 11111111 11111110
a ^ b 	= 	11111111 11111111 11111111 11110010
~a		= 	00000000 00000000 00000000 00010011

进行位操作时,除long型外,其他类型会自动转成int型,转换之后,可接受右操作数长度为32。进行位运算时,总是先将短整型和字节型值转换成整型值再进行移位操作的

数据类型 大小
byte 8 bit
short 16 bit
char 16 bit
int 32 bit
long 64bit

示例

byte a = -128;
byte b = 63;
byte result16 = (byte)(a << 1);
byte result17 = (byte)(a >> 1);
byte result18 = (byte)(a >>> 1);
byte result19 = (byte)(a & b);
byte result20 = (byte)(a | b);
byte result21 = (byte)(a ^ b);
byte result22 = (byte)(~ a);

上面的代码在位运算后类型自动提升为了int,所以需要使用int类型的变量来接受,但是我们可以在进行位运算后进行强转,但强转会直接截取字节,从而导致丢失精度,最终得到的结果如下

0
-64
-64
0
-65
-65
127

对于 int 类型的整数移位 a >> b, 当 b>32 时,系统先用 b 对 32 求余(因为 int 是 32 位),得到的结果才是真正移位的位数,例如,a >> 33 和 a >> 1 的结果相同,而 a >> 32 = a

知道了位运算的规则,那么我们什么时候可以使用到位运算?位运算的使用场景有哪些呢?

位运算的使用场景如下:

1. 判断奇偶性
public void method1(int a){
    
	if (a&1 == 0) {
    
		log.info("偶数")
	}else if ( a&1 == 1) {
    
		log.info("奇数")
	}
}

偶数的最低位肯定是0,奇数的最低位肯定是1,而1的最低位是1其他位都为零,当进行与运算时:

  • 偶数必然:a&1 == 0
  • 奇数必然:a&1 == 1
2. 不使用中间变量交换两个数
public void swap(int a , int b) {
     
    a = a ^ b;
    b = b ^ a;
    a = a ^ b;
} 

这里需要知道两点:

  1. 任何数和自己进行异或操作结果都为0
  2. 异或符合交换律,即a ^ b = b ^ a

好的,那么上面代码操作就等于:

a = a ^ b;
b = b ^ a = b ^ (a ^ b) = a;
a = a ^ b = (a ^ b) ^ (b ^ (a ^ b)) = (a ^ b) ^ a = b;
3. 判断一个正整数是不是2的整数次幂
public boolean power2(int a) {
    
	if (a <= 0){
    
		System.out.println("这里不计算负数,直接返回false");
		return false;
	} else{
    
		return (a&(a-1))==0
	}
}

任何正整数如果是2的幂数,都形如下

10
100
1000
10...0

即首位都为1,往后位数都为0,那么在减去1后又都形如下

01
011
0111
01...1

所以大于零的2的幂数和自己减一后的数进行与运算结果必然为0

4. 计算整数的平均值
public int average(int a, int b){
        
    return (a&b)+((a^b)>>1); 
} 

具体原理详见博主的另一篇博文:位运算求整数的平均值

5. 计算绝对值
public int abs( int a ) {
     
	return (a + (a >> 31)) ^ (a >> 31) ;
}

体原理详见博主的另一篇博文:位运算求整数的绝对值

6. 取模运算转化成位运算 (在不产生溢出的情况下)

注意,这里只支持正数的取模操作

a % (2^n) = a & (2^n - 1) 

取模得到的值肯定小于模数,即

11%2   	那么得到的值肯定小于2,也就是[0-2)之间, 00000000 - 00000001
101%8	那么得到的值肯定小于8,也就是[0,8)之间, 00000000 - 00000111
---------------------
现在我们再来看一下具体的模操作
11%2=1
00001011
%
00000010
得到
00000001

101%8=5
01100101
%
00001000
得到
00000101
---------------------
从上面的例子我们可以看到一个现象,一个数对2的幂数的模,其实就是被模数按照模数的位数的截取
即
如果模数是8
1000
那么不管被模数是多少,它的模都为被模数后三位所代表的值
如果被模数为20
10010
那么它的模就是010,也就是2
---------------------
当然,有一种另类情况,就是被模数小于模数,那么它们的模就等于被模数本身
例如:2%8=2

那么通过什么方式可以获取被模数的需要截取的位数呢?正好,与操作就可以做到,那为什么需要-1呢?

因为2的幂数-1永远都是形如下面的格式

1
11
111
1...1

真好是这个特性保证了a & (b-1)能够获得后几位的值,所以

a % b = a & (b-1)
7. 乘法运算转化成位运算 (在不产生溢出的情况下)
a * (2^n) = a < < n 
8. 除法运算转化成位运算 (在不产生溢出的情况下)
a / (2^n) = a >> n 
9.对称加密

就是使用一次异或加密,使用两次异或解密

public void test4(){
    
    String a = "sadfsdfsdfhfghf123dfgfg";
    System.out.println(a);
    int key = 324545231;
    byte[] bytes = a.getBytes();
    for (int i = 0; i < bytes.length-1; i++) {
    
        bytes[i] = (byte)(bytes[i] ^ key);
    }
    String b = new String(bytes);
    System.out.println(b);

    for (int i = 0; i < bytes.length-1; i++) {
    
        bytes[i] = (byte)(bytes[i] ^ key);
    }
    String c = new String(bytes);
    System.out.println(c);
}

打印结果

sadfsdfsdfhfghf123dfgfg
����������������������g
sadfsdfsdfhfghf123dfgfg
10.源码应用

可以参考JDK源码:
Spliterator(当中定义了许多Characteristic,包括ORDERED、DISTINCT、SORTED等等),在集合类在使用到它的时候,会定义不同集合拥有不同的Characteristic,详情见

ArrayList.ArrayListSpliterator的characteristics方法
HashMap.KeySpliterator的characteristics方法
...
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/weixin_37490221/article/details/90905087

智能推荐

(保姆级教程)基于STM32和MPU6050的平衡车制作报告_直立平衡小车报告-程序员宅基地

文章浏览阅读1.9w次,点赞96次,收藏855次。这可能是全网最详细的STM32平衡车制作教程(至少我是这么想的,emm大概,不接受反驳~)_直立平衡小车报告

目标检测 YOLOv5 - v6.2版本模型在瑞芯微 Rockchip设备从训练到C++部署实践_rockchip rknn-程序员宅基地

文章浏览阅读1.7k次,点赞6次,收藏29次。目标检测 YOLOv5 - v6.2版本模型在瑞芯微 Rockchip设备从训练到C++部署实践flyfish源码地址Rockchip 支持 YOLOv5 v6.2 从训练到C++部署的全链条开发,包括。_rockchip rknn

操作系统(二)——用户接口-程序员宅基地

文章浏览阅读7.7k次,点赞4次,收藏18次。文章目录2.1 命令控制界面接口2.1.1联机命令的类型2.1.2 联机命令接口2.2 Linux系统的命令控制界面2.2.1 登录Shell2.2.2 命令句法2.2.3 常用的基本命令2.2.4 重定向与管道命令2.2.5 通信命令2.2.6 后台命令2.3 程序接口2.3.1 系统调用2.3.2 系统调用的类型2.3.3 系统调用的实现2.3.4 Linux系统调用2.3.5 Windows..._用户接口

从web浏览器的渲染到性能优化_web浏览器的资源加载和渲染机制和性能优化-程序员宅基地

文章浏览阅读6.5k次,点赞3次,收藏14次。本文主要讲谈及web浏览器的渲染原理、流程以及相关的性能问题最近在复习时遇到一个问题,关于async和defer,发现自己还能记住一点,然而再往深一想,浏览器的渲染顺序?怎么防止阻塞DOM渲染?如何保证首屏优化、关键渲染路径优化?如何从浏览器渲染、网络请求、js引擎机制优化性能?好像找不到让自己满意的答案,所以查阅资料写个博客总结一下。_web浏览器的资源加载和渲染机制和性能优化

Mysq中SQL语句以及方言_mysql 的sql方言-程序员宅基地

文章浏览阅读536次。SQL语句分类DDL(Data Definition Language):数据定义语言,定义数据库对象:库、表、列等;创健、删除、修改:库、表结构DML(Data Manipulation Language):数据操作语言,定义数据库记录(数据);增、删改、:表记录DQL(Data Query Language):数据查询语言、查询记录(数据)DCL(Data Control Language):数据控制语言,定义访问权限和安全级别;对用户的创健以及授权数据库中所有字符串必须使用单引号DD_mysql 的sql方言

torch.mul()——矩阵点乘运算-程序员宅基地

文章浏览阅读1.6w次,点赞30次,收藏50次。torch.mul()torch.mul(input, other, *, out=None)输入:两个张量矩阵;输出:他们的点乘运算结果用途:①实现两个张量矩阵的点乘运算,可以实现广播功能(具体见案例代码)。②实现矩阵的数值乘法(一个常数k与矩阵做乘法,对应于广播机制)注意:若输入的两个矩阵形状不一致,则会通过广播功能进行数据扩充,然后再进行点乘整数矩阵与浮点数矩阵做点乘,结果是浮点数矩阵案例代码:①普通点乘import torch a=torch.tensor([[1,2,_torch.mul

随便推点

pacemaker+corosync实现集群管理(负载均衡、fence服务)_pacemaker fence-程序员宅基地

文章浏览阅读1k次。序言高可用集群,是指以减少服务中断(如因服务器宕机等引起的服务中断)时间为目的的服务器集群技术。简单的说,集群就是一组计算机,它们作为一个整体向用户提供一组网络资源。这些单个的计算机系统就是集群的节点。高可用集群的出现是为了减少由计算机硬件和软件易错性所带来的损失。它通过保护用户的业务程序对外不间断提供的服务,把因软件/硬件/人为造成的故障对业务的影响降低到最小程度。如果某个节点失效,它的备..._pacemaker fence

有关JAVA-IO的概述_文件io不属于内存资源-程序员宅基地

文章浏览阅读188次。有关JAVA-IO的概述主要内容java.io.File类的使用IO原理及流的分类文件流FileInputStream / FileOutputStream / FileReader / FileWriter缓冲流BufferedInputStream / BufferedOutputStream /BufferedRea_文件io不属于内存资源

tc流量控制_tc 控制流量 根据不同的ip-程序员宅基地

文章浏览阅读4.6k次。来自:http://zhangchong105.blog.163.com/blog/static/844814802012114112830295/tc的工作原理通过设置不同类型的网络接口队列,从而改变数据包发送的速率和优先级,达到流量控制的目的。内核如果需要通过某个网络接口发送数据包,它都需要按照为这个接口配置的qdisc(队列规则)把数据包加入队列,然后内核会尽可能多的从qdisc_tc 控制流量 根据不同的ip

FPGA初探CameraLINK失败_fpga中iostandard-程序员宅基地

文章浏览阅读547次。1、win64,vivado 2018.32、Block design3、约束文件set_property PACKAGE_PIN AD20 [get_ports tz_clk_p]set_property IOSTANDARD LVDS_25 [get_ports tz_clk_p]set_property PACKAGE_PIN AE18 [get_ports tz_0_p]#set_property IOSTANDARD SSTL_2 [get_ports tz_0_p]se_fpga中iostandard

【NOJ1149】【算法实验四】旅游预算_旅游预算问题算法-程序员宅基地

文章浏览阅读713次,点赞2次,收藏4次。1149.旅游预算时限:1000ms 内存限制:10000K 总时限:3000ms描述一个旅行社需要估算乘汽车从某城市到另一城市的最小费用,沿路有若干加油站,每个加油站收费不一定相同。旅游预算有如下规则: 若油箱的油过半,不停车加油,除非油箱中的油不可支持到下一站;每次加油时都加满;在一个加油站加油时,司机要花费2元买东西吃;司机不必为其他意外情况而准备额外的油;汽车开出时在起点加满油箱;计算精确到分(1元=100分)。编写程序估计实际行驶在某路线所需的最小费用。输入第一行为起点到终点的距离(实_旅游预算问题算法

新手小白看过来——带你快速入门跨境电商-程序员宅基地

文章浏览阅读1.1k次。今天的分享就到这里,希望能够给想入门跨境电商的新手小白们一点启发,只要对跨境电商有充分的了解,你就可以迈出下一步,开始着手实施,期待迎来你的第一笔收益!

推荐文章

热门文章

相关标签