关于Java按位取反“~”操作

前言

在分析一些jdk8的源码比如StampedLock的时候,发现有对long类型的变量进行“~”操作:

private static final long RBITS = 127;
private static final long SBITS = ~RBITS;

 上面的代码中,long型变量RBITS为127,通过对其进行“~”操作得到SBITS,通过Java编译器可以直接看到SBITS的值是-128,开始的时候我始终不明白这是怎样的一个演算过程,今天详细的记录在此。

按位取反

在说“~”操作即“按位取反”之前,需要注意它和平常所说的另一个概念“取反码”或者“反码”是不一样的,在Java中有原码反码补码之说,关于这三者有如下的转换规则:

(1)正数的原码,反码,补码完全一样,即符号位固定为0,数值位相同;

(2)负数的原码:最高位符号位为1,数值位表示其绝对值(其实就是和对应的正数相同),

         负数的反码:原码符号位1固定不变,数值位的每一位二进制按位取反得到反码,

         负数的补码:反码符号位1固定不变,在反码数值位最低位加1。

根据(2)负数的原码求补码的过程:补码=原码取反+1,我们可以逆运算得出,根据负数的补码求原码的方式为:负数原码=补码-1,再取反。

 因此,对一个数进行“~”操作即“按位取反”,得到的肯定不是它的“反码”,因为正数的反码固定不变,负数的反码虽说的确是进行了按位取反,但是它会保持符号位1固定不变,按位取反连符号位都会进行取反。

另外,关于补码存在的意义:补码其实是二进制数在内存中存在的形式,即不论是正数还是负数在内存中都是以其补码的形式存放的,而不是源码

接着说“~”操作即“按位取反”, 按位取反操作其实是对补码的操作,而非源码,所以在进行“~”操作之前需要先得到相应的补码。

示例

有了以上对“~”按位取反操作的相关的知识,现在再来进行对一个数进行按位取反操作就很明了了。

示例一、对最开始的long型变量127进行按位取反:

第一步:先得到补码。正数127的补码即为原码:0000000000000000 0000000000000000 0000000000000000 0000000001111111 

第二步:补码按位取反:1111111111111111 1111111111111111 1111111111111111 1111111110000000,这其实是对127按位取反之后在内存中的补码存放形式

为了知道这个按位取反的结果对应的十进制,我们需要通过补码求原码的公式,倒推得到原码之后才能知道对应的十进制是多少:

第三步:补码减1:

 1111111111111111 1111111111111111 1111111111111111 1111111110000000
-0000000000000000 0000000000000000 0000000000000000 0000000000000001
--------------------------------------------------------------------
 1111111111111111 1111111111111111 1111111111111111 1111111101111111
    结果为1111111111111111 1111111111111111 1111111111111111 1111111101111111

第四步:再根据补码减1的结果求反码得到对应的原码:  1000000000000000 0000000000000000 0000000000000000 0000000010000000,这就是-128的二进制原码

示例二、如果我们再对-128进行“~”操作结果会是多少?

第一步:“~”操作之前需要先得到-128的补码,负数的补码又需要先获得反码:

              -128原码为:1000000000000000 0000000000000000 0000000000000000 0000000010000000

              -128的反码:1111111111111111 1111111111111111 1111111111111111 1111111101111111

              反码数值位+1得补码:1111111111111111 1111111111111111 1111111111111111 1111111110000000

第二步:对-128的补码进行“~”按位取反操作结果为:

               0000000000000000 0000000000000000 0000000000000000 0000000001111111,这就是对-128按位取反之后在内存中的补码存放形式

第三步:为了知道对应的十进制,需要由补码转换为原码,由于结果是一个正数(最高位符号位为0),其原码和补码相同还是:

               0000000000000000 0000000000000000 0000000000000000 0000000001111111,所以这就是对-128进行按位取反之后的原码,十进制为127.

故而:-128进行“~”操作结果127

猜你喜欢

转载自pzh9527.iteye.com/blog/2422628
今日推荐