注:JAVA位运算在阅读JDK源码时候常常会遇到,因此学习位运算相关知识,是非常有必要的,在学习之前,首先需要了解一下二进制码相关知识,这里给大家提供几篇相关文章:《源码,补码,反码》
首先,大家都知道,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 |
七种位运算符使用实例代码:
/**
* @Auther: csp1999
* @Date: 2020/10/26/11:33
* @Description: 位运算操作符
*/
public class bit_operators {
@Test
public void test01() {
// int max = Integer.MAX_VALUE;
// int min = Integer.MIN_VALUE;
int num1 = -20;
int num2 = 30;
int bit_operator_1 = num1 << 1;// 正数左移n位扩大2^(n)倍,负数左移n位缩小2^(n)倍
int bit_operator_2 = num1 >> 1;// 正数右移n位缩小2^(n)倍,负数右移n位扩大2^(n)倍
int bit_operator_3 = num1 >>> 1;// 无符号右移 切记要明白计算机存储二进制都是以补码的形式存储
int bit_operator_4 = num1 & num2;
int bit_operator_5 = num1 | num2;
int bit_operator_6 = num1 ^ num2;
int bit_operator_7 = ~num1;
// System.out.println(max);
// System.out.println(min);
// System.out.println("0"+Integer.toBinaryString(Integer.MAX_VALUE));
// System.out.println(Integer.toBinaryString(20));
System.out.println(bit_operator_1);
System.out.println(bit_operator_2);
System.out.println(bit_operator_3);
System.out.println(bit_operator_4);
System.out.println(bit_operator_5);
System.out.println(bit_operator_6);
System.out.println(bit_operator_7);
}
}
运算结果如下:
-4
-1
2147483647
2
-2
-4
1
原理解析(高位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 num1 = -128;
byte num2 = 63;
byte bit_operator_1 = (byte)(a << 1);
byte bit_operator_2 = (byte)(a >> 1);
byte bit_operator_3 = (byte)(a >>> 1);
byte bit_operator_4 = (byte)(a & b);
byte bit_operator_5 = (byte)(a | b);
byte bit_operator_6 = (byte)(a ^ b);
byte bit_operator_7 = (byte)(~ a);
上面的代码在位运算后类型自动提升为了int,所以需要使用int类型的变量来接受,但是我们可以在进行位运算后进行强转,但强转会直接截取字节,从而导致丢失精度,最终得到的结果如下:
0
-64
-64
0
-65
-65
127
对于 int 类型的整数移位 num1 >> num2, 当 b>32 时,系统先用 num2 对 32 求余(因为 int 是 32 位),得到的结果才是真正移位的位数,例如,num1 >> 33 和 num1 >> 1 的结果相同,而 num1>> 32 = num1;
位运算的使用场景如下:
1.判断奇偶
@Test
public void test02() {
Integer num = 123;
// 判断奇偶普通方式一:
if (num % 2 == 0) {
System.out.println("偶数");
} else {
System.out.println("奇数");
}
// 判断奇偶位运算方式二:
if ((num & 1) == 0) {
System.out.println("偶数");
} else if ((num & 1) == 1) {
System.out.println("奇数");
}
}
偶数的最低位肯定是0,奇数的最低位肯定是1,而1的最低位是1其他位都为零,当进行与运算时:
- 偶数必然:a&1 == 0
- 奇数必然:a&1 == 1
2. 不使用中间变量交换两个数
@Test
public void test03() {
int a = 10;
int b = 20;
// 1.依靠中间变量交换2个数值:
int c;
c = a;
a = b;
b = c;
System.out.println("a=" + a + ",b=" + b);
// 2. 位运算不使用中间变量交换2个数:
a = 10;
b = 20;
a = a ^ b;
b = b ^ a;
a = a ^ b;
System.out.println("a=" + a + ",b=" + b);
}
这里需要知道两点:
- 任何数和自己进行异或操作结果都为0
- 异或符合交换律,即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 power(int num) {
if (num <= 0) {
System.out.println("这里不计算负数,直接返回false");
return false;
} else {
return (num & (num - 1)) == 0;
}
}
@Test
public void test04() {
int num = 1024;
System.out.println(power(num));
}
任何正整数如果是2的幂数,都形如下:
10
100
1000
10...0
1234
即首位都为1,往后位数都为0,那么在减去1后又都形如下:
01
011
0111
01...1
1234
所以大于零的2的幂数和自己减一后的数进行与运算结果必然为0
4. 对称加密
就是使用一次异或加密,使用两次异或解密:
@Test
public void test5(){
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
以上是JAVA位运算的基本实例和知识点,同样位运算也广泛应用于JDK源码中,对于初次学习JDK源码的小伙伴,位运算基本知识是需要的。最后给大家推荐一个宝藏博主:[枣面包]