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


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;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

运算结果如下

-40
-10
2147483638
12
-2
-14
19
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

原理解析如下(高位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
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

进行位操作时,除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);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

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

0
-64
-64
0
-65
-65
127
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

对于 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("奇数")}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

偶数的最低位肯定是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
  • 2
  • 3
  • 4
  • 5

这里需要知道两点:

  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;
  • 1
  • 2
  • 3

3. 判断一个正整数是不是2的整数次幂

public boolean power2(int a) {if (a <= 0){System.out.println("这里不计算负数,直接返回false");return false;} else{return (a&(a-1))==0}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

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

10
100
1000
10...0
  • 1
  • 2
  • 3
  • 4

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

01
011
0111
01...1
  • 1
  • 2
  • 3
  • 4

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

4. 计算整数的平均值

public int average(int a, int b){    return (a&b)+((a^b)>>1);
}
  • 1
  • 2
  • 3

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

5. 计算绝对值

public int abs( int a ) { return (a + (a >> 31)) ^ (a >> 31) ;
}
  • 1
  • 2
  • 3

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

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

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

a % (2^n) = a & (2^n - 1)
  • 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
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29

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

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

1
11
111
1...1
  • 1
  • 2
  • 3
  • 4

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

a % b = a & (b-1)
  • 1

7. 乘法运算转化成位运算 (在不产生溢出的情况下)

a * (2^n) = a < < n
  • 1

8. 除法运算转化成位运算 (在不产生溢出的情况下)

a / (2^n) = a >> n
  • 1

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);
<span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">int</span> i <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> i <span class="token operator">&lt;</span> bytes<span class="token punctuation">.</span>length<span class="token operator">-</span><span class="token number">1</span><span class="token punctuation">;</span> i<span class="token operator">++</span><span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span>bytes<span class="token punctuation">[</span>i<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token keyword">byte</span><span class="token punctuation">)</span><span class="token punctuation">(</span>bytes<span class="token punctuation">[</span>i<span class="token punctuation">]</span> <span class="token operator">^</span> key<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
String c <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">String</span><span class="token punctuation">(</span>bytes<span class="token punctuation">)</span><span class="token punctuation">;</span>
System<span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span>c<span class="token punctuation">)</span><span class="token punctuation">;</span>

}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

打印结果

sadfsdfsdfhfghf123dfgfg
����������������������g
sadfsdfsdfhfghf123dfgfg
  • 1
  • 2
  • 3

10.源码应用

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

ArrayList.ArrayListSpliterator的characteristics方法
HashMap.KeySpliterator的characteristics方法
...
  • 1
  • 2
  • 3

【Java基础】Java位运算相关推荐

  1. c语言10以内位运算,C语言基础知识--位运算

    1.原码,反码,补码: (1)在n位的机器数中,最高位为符号位,该位为零表示为正,为一表示为负:其余n-1位为数值位,各位的值可为零或一.当真值为正时,原码.反码.补码数值位 完全相同:当真值为负时, ...

  2. Java基础----Java编程语言概述

    Java基础----Java编程语言概述 文章目录 Java基础----Java编程语言概述 Java编程语言概述 1-1 软件开发介绍 1.1软件开发介绍 1.2 常用命令 1-2 计算机编程语言介 ...

  3. Java基础-Java中常用的锁机制与使用

    Java基础-Java中常用的锁机制与使用 锁lock或互斥mutex是一种同步机制,主要用于在存在多线程的环境中强制对资源进行访问限制.锁的主要作用为强制实施互斥排他以及并发控制策略.锁一般需要硬件 ...

  4. Java基础-Java中的堆内存和离堆内存机制

    Java基础-Java中的堆内存和离堆内存机制 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 转载于:https://www.cnblogs.com/yinzhengjie/p/9 ...

  5. Java基础-JAVA中常见的数据结构介绍

    Java基础-JAVA中常见的数据结构介绍 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.什么是数据结构 答:数据结构是指数据存储的组织方式.大致上分为线性表.栈(Stack) ...

  6. Java基础-Java中的内存分配与回收机制

    Java基础-Java中的内存分配与回收机制 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一. 二. 转载于:https://www.cnblogs.com/yinzhengji ...

  7. Java基础——Java多继承的三种实现方式

    Java基础--Java"多继承"的三种实现方式 Java语言本身只支持单继承(每个类只能有一个父类),但单继承的局限性很大,因此,可以通过以下的方式实现"多继承&quo ...

  8. 计算机基础知识---位运算的应用

    Author:baiyucraft BLog: baiyucraft's Home 前置学习: 计算机基础知识-位运算的简介   在了解位运算后,我们要明白一点:为什么要学习位运算呢.其实很重要的一个 ...

  9. [重学Java基础][Java IO流][Exter.2]IO流中几种不同的读写方法的区别

    [重学Java基础][Java IO流][Exter.2]IO流中几种不同的读写方法的区别 Read 读入方法 read(): 一般是这种形式 public int read() 1.从流数据中读取的 ...

  10. JAVA基础--JAVA SE(知识点总结 Ⅴ )

    前面内容请见: JAVA基础–JAVA SE(知识点总结 Ⅰ ) JAVA基础–JAVA SE(知识点总结 Ⅱ ) JAVA基础–JAVA SE(知识点总结 Ⅲ ) JAVA基础–JAVA SE(知识 ...

最新文章

  1. warning:partition X does not end on cylinder boundary
  2. jvm五:编译期不能确定常量的值
  3. IDA Pro安装教程
  4. [Leetcode]-containsNearbyDuplicate
  5. t-sne 流形_流形学习[t-SNE,LLE,Isomap等]变得轻松
  6. 在没有复杂插件的情况下从Eclipse启动和调试Tomcat
  7. GitHub 版本控制 项目托管 04 创建GitHub远程仓库
  8. pytorch torch.nn.Module
  9. 【bzoj4530】[Bjoi2014]大融合 LCT维护子树信息
  10. 三星android+l,高配原生安卓!移动定制版三星I9008L评测
  11. Excel 操作 第一篇 行列技巧
  12. GitHub 上受欢迎的 Android UI Library 整理(一)
  13. html5是什么语言,html5 css3是什么?
  14. python在一个函数中调用另一函数中的变量
  15. Ubuntu Kylin使用docker单机部署Fate联邦学习框架
  16. 第十二届蓝桥杯省赛 C/C++大学B组 试题G:砝码称重
  17. 每日一练 JS30天挑战 数组操作实例
  18. uboot和Linux内核移植
  19. 技术人玩小游戏,如何“不战而胜”
  20. python库-networkx模块

热门文章

  1. 你知道二维码和NFC的优缺点吗?你认为谁才是移动支付的未来?
  2. 这八个产品原则,决定了产品能走多远
  3. 荣耀盒子刷鸿蒙,荣耀盒子怎么样,网友给出3个不建议入手理由
  4. JS 以英文字母或汉字开头,限4-16个字符,一个汉字为2个字符
  5. IE11 开启F12开发人员工具中的 始终从服务器刷新
  6. 这几个手机的隐藏功能学起来,总有一天会用到
  7. linux tar 到目标目录,Linux解压到指定目录
  8. 如何向U盘里拷贝大文件?
  9. 刚毕业女大学生竟和“禽兽”做出这种事
  10. 跟随鼠标一起流动的粒子动画 JS 原生代码