前言
在分析一些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
相关推荐
操作符~, 是按位取反的意思,表面上~~(取反再取反)没有意义,实际上在JS中可以将浮点数变成整数。 代码如下: <html> [removed] var myArray = new Array(); myArray.push(“a”); myArray.push(“b”); ...
在Java中,按位操作符用于对整数进行位级别的操作 按位与(&)操作符 按位或(|)操作符 按位异或(^)操作符 按位取反(~)操作符 左移()操作符 右移(>>)操作符
位运算符可以结合这些整型变量进行各种位级操作,例如通过按位与(&)来设置或清除特定位,按位或(|)来设置位,按位异或(^)来进行位级别的XOR操作,按位右移(>>>或>>)来移动位,左移()将位向左移动,以及按位取反(~)来...
4. 按位非(~):对操作数的每一位取反,0变1,1变0。 5. 左移():将操作数的二进制位向左移动指定的位数,右边补0。 6. 右移(>>):将操作数的二进制位向右移动指定的位数,左边高位根据符号位决定补0还是补1(有符号...
4. 按位非(~):对操作数的每一位取反,0变为1,1变为0。 5. 左移():将操作数的二进制位向左移动指定的位数,右边用0填充。 6. 右移(>>):将操作数的二进制位向右移动指定的位数,左边的高位丢弃,对于有符号整数,...
值得注意的是,除按位取反(~)外,其余的都是二元运算符,即它们需要两个操作数。这些运算符只能作用于整型和字符型数据。 基础的位运算知识中,Java的整数类型(char除外)都是有符号的,即可以表示正数和负数。...
- **按位非(NOT)**:`~`,这是一个一元运算符,对操作数的每一位进行取反操作。例如,对于数字42(二进制形式为`00101010`),应用按位非运算后变为`11010101`。 - **按位与(AND)**:`&`,如果两个操作数的...
- **按位取反(~)**:将每个位取反,即0变1,1变0。 - **左移位()**:将操作数的所有位向左移动指定的位数,高位丢弃,低位补0。 - **右移位(>>)**:将操作数的所有位向右移动指定的位数,对于正数,高位补0;...
位运算在Java编程中是底层操作,用于直接处理二进制数据,对于理解计算机内部机制和优化代码性能至关重要。本文将深入探讨位运算的相关知识,包括计算机中数据的表示方法、二进制计数系统、以及原码、反码和补码的...
Java位运算在编程中是一种非常基础且强大的操作,它直接作用于二进制位,能够进行高效的数值处理和数据操作。本文将深入讲解Java中的位运算,并通过雪花算法的应用实例来进一步阐述其重要性和用法。 1. **位运算...
- **按位非 (`~`)**:对二进制数进行按位取反操作,即将每个位上的值反转。 - 示例:`~5 = -6` - `5` 的二进制表示为 `00000000000000000000000000000101`,按位非操作后得到 `11111111111111111111111111111010`...
按位非"~"运算符对一个数的所有位进行取反操作。左移"是将数字的二进制位向左移动指定的位数,相当于乘以2的幂次;右移">>"则是向右移动,相当于除以2的幂次。 在Java编程中,理解位运算和它们的应用场景对于编写...
位操作是其他很多语言都支持的操作,如C、C++和Java等,C#也不例外支持位操作。注意位操作支持的数据类型是基本数据类型,如byte、short、char、int、long等,C#支持的位操作有如下几种: •按位与 &•按位或 |•按位...
Java位运算是一种在计算机科学中广泛使用的操作,它涉及到对二进制位的直接操作,包括按位与、按位或、按位异或、按位非、左移、右移以及无符号右移等。这些操作对于理解底层计算原理、优化代码性能以及在特定场景下...
* 位运算符包括按位与、按位或、按位异或和按位非,用于对数字进行二进制操作。 * 逻辑运算符包括逻辑与、逻辑或和逻辑非,用于对布尔值进行逻辑操作。 四、流程控制 * 流程控制是Java语言中的控制结构,用于控制...