位运算符
在Java语言中,提供了7种位运算符,分别是按位与(&)、按位或(|)、按位异或(^)、取反(~)、左移(<<)、带符号右移(>>)和无符号右移(>>>)
操作符 | 语义 | 描述 | 运算规则 |
---|---|---|---|
& | 按位与 | 二进制数据按位与操作 | 如果两个二进制位上的数都是1,那么运算结果为1,其他情况运算结果均为0。 (0&0=0 1&1=1 1&0=0 0&1=0) |
| | 按位或 | 二进制数据按位或操作 | 两个二进制位上的数字如果都为0,那么运算结果为0,否则运算结果是1。(0|0=0 0|1=1 1|0=1 1|1=1) |
~ | 按位取反 | 二进制数据按位取反 | 对每个二进制位进行取反操作,所谓取反就是原来二进制位上如果是0,那么就变成1,反之,如果原来二进制位上是1,那么就变为0。即:取反就是1为0,0为1。取反运算符是一个单目运算符,所以只需要一个操作数就可以了。 |
^ | 按位异或 | 二进制数据异或,相同为假、不同为真 | 两个二进制位上的数字如果相同,则运算结果为0;如果两个二进制位上的数字不相同,则运算结果为1。(1^0 = 1 , 1^1 = 0 , 0^1 = 1 , 0^0 = 0) |
>> | 右移 | 二进制数据整体右移 | 各二进位全部右移若干位,对无符号数,高位补0;有符号数,各编译器处理方法不一样,有的补符号位(算数右移),有的补0(逻辑右移),(相当于除2)左边补符号位 |
<< | 左移 | 二进制数据整体左移 | 各二进位全部左移若干位,高位丢弃,低位补0,(相当于乘2)右边补0 |
>>> | 无符号右移 | 二进制数据整体右移,符号位补0 | (相当于除2)左边补0 |
注意事项
- 运算符当中,仅有~是单目运算符,其他运算符均为双目运算符。【就是运算符操作数的个数,单目就是一个操作数,双目就是两个操作数】
- 位运算符是对long、int、short、byte和char这5种类型的数据进行运算的,不能对double、float和boolean进行位运算操作。
- 凡是位运算符,都是把值先转换成二进制,再进行后续的处理。
- 按位运算表示按每个二进制位(bit)进行计算,其操作数和运算结果都是整型值。
- 对数值类型数据进行按位操作;1表示true、0表示false。
- 位移操作同取反操作一样,并不能改变变量本身的值,所能改变的仅是存储在操作数栈中那个数据的值.【即定义一个变量i并赋值,对i取反后i的值不发生改变】
- 当位移的位数很多时,导致最左边的符号位发生变化,就不再具有乘以2的N次方的效果了。比如十进制的5转换为补码形式是:前面29个0最后3位是101,如果移动29位,那么最前面的符号位就变成了1,此时运算的结果就成为了一个负数,不再是5乘以2的29次方的乘法结果。
- 如果位移数超过31,则虚拟机会对位移数按连续减去32,直到得到一个小于32并且大于等于0的数,然后以这个数作为最终的位移数。例如:对int型变量进行位移97位的操作,虚拟机会首先对97连续减去3个32,最终得到数字1,实际进行位移运算时只对变量位移1位。而对于long类型的数据而言,最多支持63位的位移运算,如果位移数超过63,则连续减去64,以最终得到的小于64并且大于等于0的数作为位移数。
- 带符号右移的操作可以保证移动之前和移动之后数字的正负属性不变,原来是正数,不管移动多少位,移动之后还是正数,原来是负数,移动之后还是负数。
- 对于任何一个byte、short或者int类型的数据而言,带符号右移31位之后,得到的必然是0或者是-1。对于long类型的数据而言,带符号右移63位之后,得到的也必然是0或者是-1。
关于原码、反码、补码
- 二进制的最高位是符号位:0表示整数,1表示负数
- 正数的原码、补码、反码都一样(三码合一)
- 负数的反码=它的符号位不变,其它位取反(0->1,1->0)
- 负数的补码=它的反码+1,负数的反码=负数的补码-1
- 0的反码,补码都是0
- java没有无符号数
- 在计算机运算的时候,都是以补码的方式运算
- 当我们看运算结果的时候,要看他的原码
常见用法
package com.javacore;
public class Demo {
public static void main(String[] args) {
System.out.println("-----按位与运算符-----");
/**
* 按位与运算符
*
* 00000000000000000000000000000001
* 00000000000000000000000000000010
* --------------------------------
* 00000000000000000000000000000000
*
*/
System.out.println("1&2 = " + (1&2));
System.out.println("-----按位或运算符-----");
/**
* 按位或运算符
*
* 00000000000000000000000000000001
* 00000000000000000000000000000010
* --------------------------------
* 00000000000000000000000000000011
*
*/
System.out.println("1|2 = " + (1|2));
System.out.println("-----取反运算符-----");
/**
* 取反运算符
*
* 正数取反【正数原码、反码、补码一样】
* -> 1的原码 00000000000000000000000000000001
* -> 1的补码 00000000000000000000000000000001
* -> 按位取反 11111111111111111111111111111110 【结果的补码】
* -> 结果补码的反码 10000000000000000000000000000001【负数最高位不变,其余取反】
* -> 结果反码加1得到补码的补码即为结果的原码 10000000000000000000000000000010
*
* 负数取反
* -> -1的原码 10000000000000000000000000000001
* -> -1的反码 11111111111111111111111111111110
* -> -1的补码 11111111111111111111111111111111【反码加1】
* -> 对-1补码按位取反 00000000000000000000000000000000【结果的补码】
* -> 正数三码合一,所以结果即为 00000000000000000000000000000000
*/
System.out.println("~1 = " + (~1));
System.out.println("~-1 = " + (~-1));
System.out.println("-----异或运算符-----");
/**
* 异或运算符
*
* 00000000000000000000000000000001
* 00000000000000000000000000000010
* --------------------------------
* 00000000000000000000000000000011
*/
System.out.println("1^2 = " + (1^2));
////面试题:不使用第三个变量交换两个数字
swap(10,20);
System.out.println("-----左移运算符-----");
/**
* 左移运算符
*/
int a = 7;
System.out.println("a<<2:" + (a<<2));
System.out.println("-7<<2:" + (-7<<2));
System.out.println("a<<30:" + (a<<30));
System.out.println("a:" + a);
System.out.println("-----右移运算符-----");
/**
* 右移运算符
*/
int b = 9;
System.out.println("b>>2:" + (b>>2));
System.out.println("-9>>2:" + (-9>>2));
System.out.println("b>>30:" + (b>>30));
System.out.println("-9>>30:" + (-9>>30));
System.out.println("b:" + b);
System.out.println("-----无符号右移运算符-----");
/**
* 无符号右移运算符
*/
System.out.println("20>>>2:" + (20>>>2));
System.out.println("-20>>>2:" + (-20>>>2));
System.out.println("-----判断奇偶数-----");
/**
* 判断奇偶数:该数二进制的最后一位是0的话那么就为偶数;是1的话就为奇数
*/
for (int i = 0; i < 10; i++) {
System.out.println(1 == (1&i) ? (i + "是奇数") : i + "是偶数");
}
System.out.println("-----改变正负性-----");
/**
* 正数变成负数,负数变成正数
*/
System.out.println(~11 + 1);
System.out.println(~-11 + 1);
System.out.println("-----求绝对值(一)-----");
/**
* 负数变成正数,正数不变
*/
int i = 6 >> 29;
int j = -6 >> 29;
System.out.println(i == 0 ? 6 : (~6 + 1));
System.out.println(j == 0 ? -6 : (~-6 + 1));
System.out.println("-----求绝对值(二)-----");
/**
* 负数变成正数,正数不变
*/
int m = 6 >> 29;
int n = -6 >> 29;
System.out.println((6 ^ m) - m);
System.out.println((-6 ^ n) - n);
}
/**
* 不使用第三个变量交换两个数字
* @param x
* @param y
*/
public static void swap(int x, int y) {
System.out.println("交换前 x = " + x + " y = " + y);
//加减法;缺点,如果数据大可能会出现溢出
//x=x+y;
//y=x-y;
//x=x-y;
//异或法
x=x^y;
y=x^y;
x=x^y;
System.out.println("交换后 x = " + x + " y = " + y);
}
}
结果:
-----按位与运算符-----
1&2 = 0
-----按位或运算符-----
1|2 = 3
-----取反运算符-----
~1 = -2
~-1 = 0
-----异或运算符-----
1^2 = 3
交换前 x = 10 y = 20
交换后 x = 20 y = 10
-----左移运算符-----
a<<2:28
-7<<2:-28
a<<30:-1073741824
a:7
-----右移运算符-----
b>>2:2
-9>>2:-3
b>>30:0
-9>>30:-1
b:9
-----无符号右移运算符-----
20>>>2:5
-20>>>2:1073741819
-----判断奇偶数-----
0是偶数
1是奇数
2是偶数
3是奇数
4是偶数
5是奇数
6是偶数
7是奇数
8是偶数
9是奇数
-----改变正负性-----
-11
11
-----求绝对值(一)-----
6
6
-----求绝对值(二)-----
6
6
转载自:
https://blog.csdn.net/yinying293/article/details/128481204
https://blog.csdn.net/weixin_65584018/article/details/126931663
https://mp.weixin.qq.com/s?__biz=MzI0OTQwNDQxMw==&mid=2247483760&idx=1&sn=27cbdd41da43b5b71c9f7a3ae807fae6&chksm=e9934fe2dee4c6f4869f6d46004c2f3a76c3b5aefc1d1acc8acd9504c64e9a8143f21fe2c968&scene=27