在说位运算之前,先说一下二进制的特殊问题:
计算机数据的存储使用二进制补码形式存储,并且最高位是符号位,1是负数,0是正数。
规定:正数的补码与反码、原码一样,称为三码合一;
负数的补码与反码、原码不一样:
负数的原码:把十进制转为二进制,然后最高位设置为1
负数的反码:在原码的基础上,最高位不变,其余位取反(0变1,1变0)
负数的补码:反码+1
例如:byte类型(1个字节,8位)
25 ==> 原码 0001 1001 ==> 反码 0001 1001 -->补码 0001 1001
-25 ==>原码 1001 1001 ==> 反码1110 0110 ==>补码 1110 0111
底层是用加法代替减法:-128==》-127-1==》-127+(-1)
-127- -1 ==> -127 + 1
1.位运算的符号
(1)左移:<< PS :左移无论正负都是补0
(2)右移:>> PS:当为正数时补0,负数时补1
(3)无符号右移:>>> PS:补0
(4)按位与:&
(5)按位或:|
(6)按位异或:^
(7)按位取反:~
PS: &、|、^是逻辑运算符还是位运算符,看它们的操作数是整数就是位运算符,是boolean就是逻辑运算符。
(以代码为基础进行讲解)
class Bit{
public static void main(String[] args){
//简单的算:左移几位,相当于乘以2的几次方
//2 * 2的5次
//实际的算:
//2的补码: 0000 0000 0000 0000 0000 0000 0000 0010
//2<<5: 000 0000 0000 0000 0000 0000 0010 0 0000 左边的被移走,右边补0
System.out.println(2 << 5);
//简单的算:右移几位,相当于除以2的几次方,如果除不尽,向下取整
//250 / 2的5次
//实际的算:
//250的补码 0000 0000 0000 0000 0000 0000 1111 1010
//250>>5 0000 0 0000 0000 0000 0000 0000 0000 111 右边被移走了,左边补0
System.out.println(250 >> 5);
//简单的算:右移几位,相当于除以2的几次方,如果除不尽,向下取整
//实际的算:
//-250的
//原码:1000 0000 0000 0000 0000 0000 1111 1010
//反码:1111 1111 1111 1111 1111 1111 0000 0101
//补码:1111 1111 1111 1111 1111 1111 0000 0110
//-250>>5 11111 1111 1111 1111 1111 1111 1111 000 右边被移走了,左边补1
//结果补码:11111 1111 1111 1111 1111 1111 1111 000
//反码:11111 1111 1111 1111 1111 1111 1110 111
//原码:10000 0000 0000 0000 0000 0000 0001 000
System.out.println(-250 >> 5);//-8
//正数的无符号右移和右移是一样的
System.out.println(250 >>> 5);//7
//负数的无符号右移是不同的,当右边被移走了,左边无论最高位是什么都补0
//-250的
//原码:1000 0000 0000 0000 0000 0000 1111 1010
//反码:1111 1111 1111 1111 1111 1111 0000 0101
//补码:1111 1111 1111 1111 1111 1111 0000 0110
//-250>>>5
//000001111 1111 1111 1111 1111 1111 000
//最高位是0,说明是正数
//结果的补码也是原码,000001111 1111 1111 1111 1111 1111 000
System.out.println(-250 >>> 5);//134217720
/*
250的补码 0000 0000 0000 0000 0000 0000 1111 1010
234的补码 0000 0000 0000 0000 0000 0000 1110 1010
250 & 234 0000 0000 0000 0000 0000 0000 1110 1010 234
0 & 0 是0
0 & 1 是0
1 & 0 是0
1 & 1 是1
*/
System.out.println(250 & 234);//234
/*
250的补码 0000 0000 0000 0000 0000 0000 1111 1010
234的补码 0000 0000 0000 0000 0000 0000 1110 1010
250 | 234 0000 0000 0000 0000 0000 0000 1111 1010 250
0 | 0 是0
0 | 1 是1
1 | 0 是1
1 | 1 是1
*/
System.out.println(250 | 234);//250
/*
250的补码 0000 0000 0000 0000 0000 0000 1111 1010
234的补码 0000 0000 0000 0000 0000 0000 1110 1010
250 ^ 234 0000 0000 0000 0000 0000 0000 0001 0000
0 ^ 0 是0
0 ^ 1 是1
1 ^ 0 是1
1 ^ 1 是0
*/
System.out.println(250 ^ 234);//16
/*
3的补码:0000 0000 0000 0000 0000 0000 0000 0011
~3 1111 1111 1111 1111 1111 1111 1111 1100
结果的补码:1111 1111 1111 1111 1111 1111 1111 1100
反码:1111 1111 1111 1111 1111 1111 1111 1011
原码:1000 0000 0000 0000 0000 0000 0000 0100
*/
System.out.println(~3);//-4
}
}
贴一张运算符优先级的表: