位运算符

在java编写代码的过程中有效地运用位运算符可以节约内存并且提高运算效率。
位运算符用来对二进制位进行操作,共有7种类运算符,如下:

符号

意义

&

按位与

|

按位或

^

按位异或

~

按位取反

>>

右移

<<

左移

>>>

无符号右移动

聊一聊什么是位运算?

再聊位运算之前,我们先来聊一聊啥是“位”,这里的位是二进制位的位。二进制位简称“位”,是二进制记数系统中表示小于2的整数的符号,一般用1或 0表示。
在计算机底层中int整型占四个字节,那每一个字节又有8位,举个例子:int i =5;

int i=5;
//把int类型的十进制数5 转换为二进制数:
//00000000 00000000 00000000 00000101

在计算机中二进制最高位为符号为“0”正好,“1”为负号。
计算机中只能存在二进制, 所以计算需要使用二进制的补码进行计算。
1、正数的原码、补码、反码均为其本身;
2、负数(二进制)的原码、补码、反码公式:
反码 = 原码(除符号位外)每位取反
补码 = 反码 + 1
举个例子:int i=-5;
把十进制数-5转化为2进制数: 10000000 00000000 00000000 00000101
原码: 10000000 00000000 00000000 00000101
反码: 11111111 11111111 11111111 11111010
补码: 11111111 11111111 11111111 11111011

通过简单地介绍完啥是二进制之后,我们回归主体聊一聊java中的位运算符

1.&按位与运算

首先我们先用一个例子体会一下这个运算过程

int a=5;
int b=3;
System.out.println(a^b);

打印出的结果为: 1
这是为啥呢?这就涉及到计算机底层的按位运算了,接下来我们好好聊一聊这个话题。
int 5的补码为 00000000 00000000 00000000 00000101
int 3的补码为 00000000 00000000 00000000 00000011
下面我们来进行按位与运算,运算的原理如下:
1)&按位与运算时遇0则0;
2)任意整数&1==0,则该数为偶数;
3)整数&任意整数为正数
代码2进制运算过程:
00000000 00000000 00000000 00000101 ~>5
00000000 00000000 00000000 00000011 ~>3
00000000 00000000 00000000 00000001 5&3~>1
从上面的操作中可以看出5和3的补码在进行按位与运算的时候可以看成是同位数值在进行按位与&运算当有一个数值是0的话出来的相应位数的2进制是0,如果两个数值都是1的话,则出来的该位数的2进制值为是1

2.|按位或运算

int a=5;
int b=3;
System.out.println(a|b);

打印出的结果为:7
按位或|运算原理:
1)按位或|运算时遇见1则1;
2)任意整数|0还是本身
3)负数|任意整数是负数
代码2进制运算过程:
00000000 00000000 00000000 00000101 ~>5
00000000 00000000 00000000 00000011 ~>3
00000000 00000000 00000000 00000111 5|3~>7
从上面的操作中可以看出5和3的补码在进行按位与运算的时候可以看成是同为数值在进行按位或|运算是相同位数的二进制值有1的话,结果就是1,如果相同位数的2进制都是0的话结果为0

3.^按位异或

int a=5;
int b=3;
System.out.println(a^b);

打印的结果为:6
按位异或^运算原理:
1)相同则0不同则1
代码2进制运算过程:
00000000 00000000 00000000 00000101 ~>5
00000000 00000000 00000000 00000011 ~>3
00000000 00000000 00000000 00000111 5^3~>6
可以从运算过程中看出同位二进制数值相同的话结果为0,不同则为1

在这里补充一下按位异或(^)的扩展应用:

扩展:

我们在这一模块聊一聊如何使用按位异或(^)进行数值交换。

首先我们先聊一聊第一种情况

int a=5;
int b=a^a;
System.out.println(b);

打印的结果为:0
同一个数进行进行按位异或运算的话结果会变成0
第二种情况:

int a=0;
int b=3;
System.out.println(a^b);

结果为3

第三种情况:

int a=5;
int b=3;
a=a^b;
b=a^b;// b=a^b^b=a
a=a^b;// a=a^b^a=b
System.out.println(a);
System.out.println(b);

结果为: a=3 ,b=5 这样我们就完成了数值交换
上面讲述的方式是一种进行两个数之间数值交换的方法,它的优点是计算机在底层直接通过2进制计算进行数值交换的操作,提高了运算时间,提高了效率。但是他也有缺点,它的缺点是不能对所有的数据类型进行交换,且对别人阅读这段代码的时候也不太好理解。

4.~按位取反

int a=5;
System.out.println(~a);

打印的结果为:-6
按位取反运算原理:
1)每一位二进制值都取反
代码2进制运算过程:
00000000 00000000 00000000 00000101 原码 5
11111111 11111111 11111111 11111010 反码
11111111 11111111 11111111 11111001 补码
然后进行取反
10000000 00000000 00000000 00000110 变为原码:-6

5.>>右移

int a=10;
System.out.println(a>>2);

打印的结果为:2
右移运算原理:
1、int a=10; 把10转换为2进制数:
00000000 00000000 00000000 00001010
2、进行右移>>2操作:
(00)00000000 00000000 00000000 000010[10]
3、右移后变为:
00000000 00000000 00000000 00000010
上述运算的第二步中小括号的内容是右以后新加的二进制数,中括号的内容是右移后移除的二进制。所以就把1010(10)变成了10(20)。
总结:1) >>右移操作是 右移几就是底层而进制数值向右移动几
2)整数向右添加0
3)负数向右添加1

6.<<左移

int a=10;
System.out.println(a<<2);

打印的结果为:40
左移运算原理:
1、int a=10; 把10转换为2进制数:
00000000 00000000 00000000 00001010
2、进行左移<<2操作:
[00]000000 00000000 00000000 00001010(00)
3.左移后变为:
00000000 00000000 00000000 00101000 ~》十进制40
他的原理跟右移相同区别是移动方向是左边。
总结:1) <<左移操作是 右移几就是底层而进制数值向右移动几
2)不管被移动的数是加的都是0

7.>>>无符号右移

无符号右移的原理跟右移相同,唯一的区别在于不管正数负数它向右移动的数据都是0
请读者自行验证^ ^