前言
最近在看 hashMap 的源码, 看到了一些位运算符, 决定深入研究学习一下位运算符
位运算
定义: 程序中的所有数在计算机内存中都是以二进制的形式储存的位运算说穿了, 就是直接对整数在内存中的二进制位进行操作
位运算符
Java 中的位运算符一共有:&|^ <<>>>>>~ 这 7 种
- 1.&(与)|(或)^(异或)
- public static void main(String[] args) {
- int a = 10;
- System.out.println("a 的二进制表示:" + Integer.toBinaryString(a));
- int b = 11;
- System.out.println("b 的二进制表示:" + Integer.toBinaryString(b));
- int i = a & b;
- System.out.println("a & b =" + i + ",i 的二进制表示:" + Integer.toBinaryString(i));
- i = a | b;
- System.out.println("a | b =" + i + ",i 的二进制表示:" + Integer.toBinaryString(i));
- i = a ^ b;
- System.out.println("a ^ b =" + i + ",i 的二进制表示:" + Integer.toBinaryString(i));
- }
运行结果
a 的二进制表示: 1010
b 的二进制表示: 1011
a & b = 10,i 的二进制表示: 1010
a | b = 11,i 的二进制表示: 1011
a ^ b = 1,i 的二进制表示: 1
可以通过 Java 中 Integer 类自带将 int 转为二进制表示的方法查看二进制
这里 a ^ b 的二进制表示可以看成 0001
可以看出
& (与): 当 a 和 b 二进制表示上相同位数都为 1 时, i 的对应位数上的值才为 1(既 11-->1 10 -->0 01-->0 00-->0), 不难看出 i <= min(a,b)
| (或): 当 a 和 b 二进制表示上相同位数都为 0 时, i 的对应位数上的值才为 0(既 11-->1 10 -->1 01-->1 00-->0), 不难看出 i >= max(a,b)
^(异或): 当 a 和 b 二进制表示上相同位数相同时, i 的对应位数上的纸值为 0(既 11-->0 10 -->1 01-->1 00-->0)
- 2. <<(左移)>>(带符号右移)>>>(无符号右移)
- public static void main(String[] args) {
- int i = 1 << 2;
- System.out.println("1 << 2 =" + i);
- i = 1 << 30;
- System.out.println("1 << 30 =" + i);
- i = 1 << 31;
- System.out.println("1 << 31 =" + i);
- i = 1 >> 1;
- System.out.println("1 >> 1 =" + i);
- i = 1 >> 32;
- System.out.println("1 >> 32 =" + i);
- i = -1 >> 1;
- System.out.println("-1 >> 1 =" + i);
- i = -1 >>> 1;
- System.out.println("-1 >>> 1 =" + i);
- }
运行结果
- 1 << 2 = 4
- 1 << 30 = 1073741824
- 1 << 31 = -2147483648
- 1 >> 1 = 0
- 1 >> 32 = 1
- -1 >> 1 = -1
- -1 >>> 1 = 2147483647
一般情况下
- a << n = (a * (2 的 n 次方 ))
- a >> n=(a-a%2)/(2 的 n 次方)
但是, 可以看到上面的例子中可以列出不少返例
这其中主要因为 Java 中 int 的范围
首先, Java 中 int 的范围是 -2 的 32 次~ 2 的 32 次 - 1
另外, 我们有没有考虑过 i 的边界问题, 当 i = 2 的 32 次 - 1 后, 再 + 1, 会出现什么后果?
- public static void main(String[] args) {
- int i = Integer.MAX_VALUE +1;
- System.out.println(i);
- System.out.println(Integer.toBinaryString(i));
- }
运行结果
- -2147483648(-2 的 32 次方 int 的最小值)
- 10000000000000000000000000000000
我们知道 int 的长度是 32 位的, 要表示 Int 的正负, Java 中的做法是在第 32 位上做标记, 第 32 位 = 0 时, int 为正数, 第 32 位 =-1 时, int 为负数
所以
二进制: 00000000000000000000000000000000 , 代表最小的正数 0
二进制: 10000000000000000000000000000000 , 代表最小的负数 - 2147483648
从二进制计算的角度不难理解, Integer.MAX_VALUE+1 = Integer.MIN_VALUE
这就是为什么 1<<31 = -2147483648
我们再来看
1 >> 1 = 0 和 1 >> 32 = 1
这里我理解为 二进制中移位运算实际是对一个长度为 63 的二进制数进行操作, 其中连续的 32 位表示 int 的值, 剩余部分全部为 0
然后再讲这整个 63 位的二进制数看成一个圆 (循环队列)
所以, 无论一个数左移或者右移 32 位, 始终是这个数本身
然后, 我们来看一下 -1 >>1 = -1 和 -1>>>1 = 2147483647
先从字面上理解,>> 带符号右移,>>> 无符号右移
再进一步解释就很容易了, 63 位长度的二进制数中, 其中连续的 32 位表示 int 的值, 剩余的 31 位再做 >> 操作时, 保持与 int 的符号相同的值 (即 int 位负, 其余 31 位都为 1,int 为正, 其余 31 位都为 0)
而 >>> 无符号右移, 则是无论 int 为何, 其余 31 位全部为 0
- 3.~(取反)
- public static void main(String[] args) {
- int i = 10;
- System.out.println(Integer.toBinaryString(i));
- System.out.println(Integer.toBinaryString(~i));
- }
运行结果
- 1010
- 11111111111111111111111111110101
取反很容易理解, 将 0 替换成 1, 将 1 替换成 0
将 10 的二进制表示补充至完整的 32 位
00000000000000000000000000001010 取反则等于 11111111111111111111111111110101
可以看出 i + ~i = -1
来源: http://www.bubuko.com/infodetail-2513542.html