位运算符
位运算符 | 符号解释 |
---|---|
& | 按位与,当两位相同时为1时才返回1 |
| | 按位或,只要有一位为1即可返回1 |
~ | 按位非,将操作数的每个位(包括符号位)全部取反 |
^ | 按位异或。当两位相同时返回0,不同时返回1 |
<< | 左移运算符 |
>> | 右移运算符 |
>>> | 无符号右移运算符 |
左移:<<
运算规则:左移几位就相当于乘以2的几次方
右移:>>
运算规则:右移几位就相当于除以2的几次方
无符号右移:>>>
运算规则:往右移动后,左边空出来的位直接补0,不看符号位
注意:当左移的位数n超过该数据类型的总位数时,相当于左移(n-总位数)
byte,short,char在计算时按照int类型处理
二进制与十进制互转
原码,补码,反码
计算机底层就是用二进制的补码进行计算的,然后以原码转为10进制进行显示
计算机数据的存储使用二进制补码形式存储,并且最高位是符号位,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
总结
左移:<<
运算规则:左移几位就相当于乘以2的几次方
右移:>>
运算规则:右移几位就相当于除以2的几次方
无符号右移:>>>
运算规则:往右移动后,左边空出来的位直接补0,不看符号位
注意:当左移的位数n超过该数据类型的总位数时,相当于左移(n-总位数)
byte,short,char在计算时按照int类型处理
按位与:&
运算规则:
1 & 1 结果为1
1 & 0 结果为0
0 & 1 结果为0
0 & 0 结果为0
按位或:|
运算规则:
1 | 1 结果为1
1 | 0 结果为1
0 | 1 结果为1
0 & 0 结果为0
按位异或:^
运算规则:
1 ^ 1 结果为0
1 ^ 0 结果为1
0 ^ 1 结果为1
0 ^ 0 结果为0
按位取反:~
运算规则:~0就是1
~1就是0
如何区分&,|,^是逻辑运算符还是位运算符?
如果操作数是boolean类型,就是逻辑运算符,如果操作数是整数,那么就位运算符。
具体实现过程
按位与&
public class Test11 {
public static void main(String[] args) {
System.out.println(1 & 1); // 1
// &(按位与) 当两位相同时为1时才返回1
//0000 0000 0000 0001 1的原码(三码合一)
//0000 0000 0000 0001 1的反码
//0000 0000 0000 0001 1的补码
//计算过程
//0000 0000 0000 0001 1的补码
//0000 0000 0000 0001 1的补码
//0000 0000 0000 0001 结果的补码
//0000 0000 0000 0001 结果的原码 ,所以就为1
}
}
按位或 |
public class Test1 {
public static void main(String[] args) {
System.out.println(1|1);//1
//按位或,只要有一位为1即可返回1
//0000 0000 0000 0001 1的原码(三码合一)
//0000 0000 0000 0001 1的反码
//0000 0000 0000 0001 1的补码
//计算过程
//0000 0000 0000 0001 1的补码
//0000 0000 0000 0001 1的补码
//0000 0000 0000 0001 结果的补码
//0000 0000 0000 0001 结果的原码,所以结果为1
}
}
左运算符
public class Test2 {
public static void main(String[] args) {
System.out.println(5<<2);//20
//左移:<<
//运算规则:左移几位就相当于乘以2的几次方
//5的二进制位101
//0000 0000 0000 0101 5的原码(三码合一)
//0000 0000 0000 0101 5的补码
//左移动两位
//一个数的二进制补码左移若干位,右侧补0.
//0000 0000 0000 0101 5的补码
//00 0000 0000 0101 ---》 0000 0000 0001 0100 结果的补码
//0000 0000 0001 0100 结果的原码 20
}
}
右运算符
// 00000000 00000000 00000000 00000101 5的原码(补码)
// 00000000 00000000 00000000 00000001 结果的补码(原码) 1
// 一个数右移N位,相当于这个数除以2的N次方
System.out.println(5 >> 2);// 右移若干位,右侧超出的部分直接丢失,左侧整数补0负数补1.
// 10000000 00000000 00000000 00000101 -5的原码
// 11111111 11111111 11111111 11111010 -5的反码
// 11111111 11111111 11111111 11111011 -5的补码
// 11111111 11111111 11111111 11111110 -5的补码 >> 2 结果补码
// 11111111 11111111 11111111 11111101 -5的补码 >> 2 结果反码
// 10000000 00000000 00000000 00000010 -5的补码 >> 2 结果原码 -2
System.out.println(-5 >> 2);
无符号运算符
// 10000000 00000000 00000000 00000101 -5的原码
// 11111111 11111111 11111111 11111010 -5的反码
// 11111111 11111111 11111111 11111011 -5的补码
// 11111111 11111111 11111111 11111011 -5的补码 >>> 2
// 00111111 11111111 11111111 11111110 -5的补码(原码) >>> 2
System.out.println(-5 >>> 2);