JAVA基础提高之位运算

举报
兴趣使然的草帽路飞 发表于 2021/06/08 23:54:35 2021/06/08
【摘要】 注:JAVA位运算在阅读JDK源码时候常常会遇到,因此学习位运算相关知识,是非常有必要的,在学习之前,首先需要了解一下二进制码相关知识,这里给大家提供几篇相关文章:《源码,补码,反码》 首先,大家都知道,JAVA定义的位运算符可以应用于整数类型(int),长整型(long),短整型(short),字符型(char),和字节类型(byte)等类型。 Java七种...

: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); }
}

  
 
  • 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
  • 30
  • 31
  • 32
  • 33
  • 34

运算结果如下:

-4
-1
2147483647
2
-2
-4
1

  
 
  • 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 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);

  
 
  • 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 类型的整数移位 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("奇数"); }
}

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

偶数的最低位肯定是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);
}

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

这里需要知道两点:

  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 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));
}

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

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

10
100
1000
10...0
1234

  
 
  • 1
  • 2
  • 3
  • 4
  • 5

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

01
011
0111
01...1
1234

  
 
  • 1
  • 2
  • 3
  • 4
  • 5

所以大于零的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);
}

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

打印结果:

sadfsdfsdfhfghf123dfgfg
����������������������g
sadfsdfsdfhfghf123dfgfg

  
 
  • 1
  • 2
  • 3

以上是JAVA位运算的基本实例和知识点,同样位运算也广泛应用于JDK源码中,对于初次学习JDK源码的小伙伴,位运算基本知识是需要的。最后给大家推荐一个宝藏博主:[枣面包]

文章来源: csp1999.blog.csdn.net,作者:兴趣使然の草帽路飞,版权归原作者所有,如需转载,请联系作者。

原文链接:csp1999.blog.csdn.net/article/details/109286491

【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。