Java运行符学习笔记

前言

我们可能经常看到以下这样的代码,看得真是云里雾里。 下面我们来学习一下这些符号,它们是如何工作的吧。

读写锁中源码

11111.png

线程池中源码

12222.png

这里涉及到一些二进制的知识。

下面正式开始吧!

介绍以下运算符计算

~ & ^ |

这里用int来计算, 然而int 为32位(具体可以Integer.SIZE,Long为64位。)。让我们逐个击破吧!

& 与运算

&与运算 ,两个操作数中位都为1,结果才为1,否则结果为0,

1
2
3
4
5
6
7
8
9
10
11
12
int a=129;//10000001
int b=127;//01111111 ,正数前面0为补位。
int c=-2; //-2为,01,因为是负数前面不是补0,是补1,补够32位。(前面说了int 为32位。)11111111111111111111111111111110 ,

System.out.printf("二进制 %s : %s%n",a,Integer.toBinaryString(a));
System.out.printf("二进制 %s : %s%n",b,Integer.toBinaryString(b));
System.out.printf("二进制 %s : %s%n",c,Integer.toBinaryString(c));
System.out.println("&与运算:"+(a&b));
System.out.println("&与运算:"+(a&c));
System.out.println("&与运算:"+(b&c));


运行结果

二进制 129 : 10000001

二进制 127 : 1111111

二进制 -2 : 11111111111111111111111111111110

&与运算:1

&与运算:128

&与运算:126


来详细计算一下,再下面的例子就不详细计算了,因为计算方式都是类似的。 二进制 129 : 10000001,这里是要补够32位。(int为32位)

下面是129 & 127

敲重点 按照&与运算 ,两个操作数中位都为1,结果才为1,否则结果为0。 正数前面补0,,负数前面补1,补够32位,下面的例子会详细展开负数的计算。

00000000000000000000000010000001

00000000000000000000000001111111

00000000000000000000000000000001 //这个为结果,结果为1.

129 & -2

负数的补码计算方式特别一些。

符号位是表示最高那一位,就是左边第一位。比如01111111 ,这里的0就是最高位。

⑴如果补码的符号位为“0”,表示是一个正数,其原码就是补码。

⑵如果补码的符号位为“1”,表示是一个负数,那么求给定的这个补码的补码就是要求的原码。

我们来算算-2的补码吧。

2 的二进制是 00000000000000000000000000000010

第一步 取反 11111111111111111111111111111101

第二步 加1 得 11111111111111111111111111111110 //-2的补码

00000000000000000000000010000001

11111111111111111111111111111110

00000000000000000000000010000000 //这个为结果,结果为128.

| 或运算符

两个位只要有一个为1,那么结果就是1,否则就为0。

1
2
3
4
5
6
7
8
9
10
11
12
13
//或运算符用符号“|”
//两个位只要有一个为1,那么结果就是1,否则就为0
int a=129;//00000000000000000000000010000001

int b=128;//00000000000000000000000010000000
int c=-2; //11111111111111111111111111111110 负数补码方式参考上面

System.out.println("|或运算:"+(a|b));
System.out.println("|或运算:"+(a|c));
System.out.println("|或运算:"+(b|c));



运行结果

注意:高位为1,即负数。结果要保留高位,其他取反,加一。得到结果。

1
2
3
4
5

|或运算:129
|或运算:-1
|或运算:-2

~ 非运算符

非运算符用符号“~”表示,其运算规律如下:

如果位为0,结果是1,如果位为1,结果是0

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

int a=129;//10000001
int b=128;//10000000
int c=127;//01111111 ,前面0为补位。
int d=2;//10
int e=-3;//11

System.out.println("~非运算:"+~a);
System.out.println("~非运算:"+(~b));
System.out.println("~非运算:"+(~c));
System.out.println("~非运算:"+(~d));
System.out.println("~非运算e:"+(~e));


运行结果

1
2
3
4
5
6
7

~非运算:-130
~非运算:-129
~非运算:-128
~非运算:-3
~非运算e:2

~非详细计算例子

注意这个是人工的计算方式:

二进制 129:
00000000000000000000000010000001

第一步取反,结果得: 11111111111111111111111101111110 //这个机器会直接输出-130,像下面这样

//0b代表二进制

System.out.println(“~129:”+0b11111111111111111111111101111110);

简单来说就是 129+1=130,取反,变负数,-130。

简单来说就是 -3+1=-2,取反,变正数,2。

那结果11111111111111111111111101111110,是怎么转换成-130的呢?

人工计算一下。

第一步,保留高位符号,其他去反,

得: 10000000000000000000000010000001

加一 10000000000000000000000010000010

高位不参与计算,得出结果就130,由于高位是1,为负数,得-130。

^异或运算符

异或运算符是用符号“^”表示的,其运算规律是:

两个操作数的位中,相同则结果为0,不同则结果为1

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

//两个操作数的位中,相同则结果为0,不同则结果为1
int a=129;//10000001
int b=2; //10,记得要补位。
int c=-3;//11111111111111111111111111111101 //补码

//System.out.printf(Integer.toBinaryString(c));
System.out.printf("^异或运算 %s ^ %s : %s %n",a,b,a^b);
System.out.printf("^异或运算 %s ^ %s : %s %n",b,c,b^c);
System.out.printf("^异或运算 %s ^ %s : %s %n",a,c,a^c);


运行结果

1
2
3
4
^异或运算 129 ^ 2 : 131 
^异或运算 2 ^ -3 : -1
^异或运算 129 ^ -3 : -132

运算符 << , >> , >>>

<< 左移运算符,将运算符左边的对象向左移动运算符右边指定的位数(在低位补0) x<<3
> > “有符号”右移运算 符,将运算符左边的对象向右移动运算符右边指定的位数。使用符号扩展机制,也就是说,如果值为正,则在高位补0,如果值为负,则在高位补1.x>>3
> > > “无符号”右移运算 符,将运算符左边的对象向右移动运算符右边指定的位数。采用0扩展机制,也就是说,无论值的正负,都在高位补0.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

/**
* 2进制为00000010,后移3为了00010000 ,等于 16
*/
System.out.println("<<:"+(2<<3));
/**
* 16进制为00010000,前移2为了00000100 等于4
*/
System.out.println(">>:"+(16>>2));
System.out.println(">>:"+(-16>>2));
System.out.println(">>>:"+(-8>>>1));
System.out.println(">>>:"+(-0b00001000));
System.out.println(">>>:"+(-0b00000100));



运行结果

1
2
3
4
5
6
7
<<:16
>>:4
>>:-4
>>>:2147483644
>>>:-8
>>>:-4

总结

本人知识有限,如有描述错误之处,愿虎正。

你看这个像不像你欠我的赞。
谢谢大家。

你的赞就像冬日暖阳,温暖心窝。