位运算符(难点、非重点)
1. 基本语法
运算符 | 运算 | 范例 |
---|---|---|
<< | 左移 | 3 << 2 = 12 --> 3 * 2 * 2 = 12 |
>> | 右移 | 3 >> 1 = 1 --> 3 / 2 = 1 |
>>> | 无符号右移 | 3 >>> 1 = 1 --> 3 / 2 = 1 |
& | 与运算 | 6 & 3 = 2 |
| | 或运算 | 6 | 3 = 7 |
^ | 异或运算 | 6 ^ 3 = 5 |
~ | 取反运算 | ~6 = -7 或者 ~-7 = 6 |
/**
测试运算符的使用5:位运算符
1. << >> >>> & | ^ ~
2. 说明:
① << >> >>> & | ^ ~: 针对数值类型的变量或常量进行运算,运算的结果也是数值
② << : 每向左移动一位,结果就在原有的基础上 * 2(对于正数、负数都适用)
>> : 每向右移动一位,结果就在原有的基础上 / 2(对于正数、负数都适用)
3. 面试题:高效的方式计算 2 * 8?
2 << 3 相当于 2 * 2 ^ 3
或者 8 << 1(8 左移 1位)
*/
class BitTest{
public static void main(String[] args){
int num1 = 7;
System.out.println("num1左移一位时,结果是: " + (num1 << 1));
// 输出结果是14 7 * 2 ^ 1 = 14
System.out.println("num1左移二位时,结果是: " + (num1 << 2));
// 输出结果是28 7 * 2 ^ 2 = 28
System.out.println("num1左移三位时,结果是: " + (num1 << 3));
// 输出结果是56 7 * 2 ^ 3 = 56
int num2 = -7;
System.out.println("num2左移一位时,结果是: " + (num2 << 1));
// 输出结果是-14 -7 * 2 ^ 1 = -14
System.out.println("num2左移二位时,结果是: " + (num2 << 2));
// 输出结果是-28 -7 * 2 ^ 2 = -28
System.out.println("num2左移三位时,结果是: " + (num2 << 3));
// 输出结果是-56 -7 * 2 ^ 3 = -56
}
}
注意:
- 当左移的位数n超过该数据类型的总位数时,相当于左移(n - 总位数)位
- 这句话的意思是:当对一个数据类型执行左移操作时,如果左移的位数n超过了该数据类型的总位数,那么实际上等价于将左移的位数减去该数据类型的总位数(n-总位数)后再进行左移。换言之,只有左移的位数小于总位数才是有效的左移,超过总位数时需要对位数进行调整。
举例:
- 3 << 4 相当于 3 * 2 的4次幂 => 3 * 16 = 48
- -3 << 4 相当于 -3 * 2 的四次幂 => -3 * 16 = -48
- 右移时如果不能整除,向下取整。正数补0,负数补1。
- 无符号右移:>>>
运算规则:往右移动后,左边空出来的位直接补0。(正数、负数都适用)
- 举例: 69 >>> 4 类似于 69 / 2 的 4次 = 69 /16 = 4
- -69 >>> 4 结果: 268435451
/*
-69的二进制:
补码: 1000 0000 0000 0000 0000 0000 0100 0101
反码: 1111 1111 1111 1111 1111 1111 1011 1010
补码: 1111 1111 1111 1111 1111 1111
1011 1011
-69 >>> 4: 0000 1111 1111 1111 1111 1111
1111 1011
最高位是0,是正数,那么原码,反码,补码都一样
计算用补码,看结果用原码
一般情况下。乘以二用<<,除以二用>>。
那什么情况下用无符号右移>>>?
一般情况下,使用无符号右移 ">>>" 操作符可以对某些无符号整型数据进行操作。例如:IPv4地址的存储就是采用无符号整型数据类型的方式来表示。在对这种类型的数据进行操作时,经常需要用到无符号右移 ">>>" 操作符。
另外,在对一些大数据量进行移位运算时,使用无符号右移操作符 ">>>" 可能会比有符号右移操作符 ">>" 效率更高,因为它不需要考虑符号位的处理,执行效率可能更高。
*/
案例:如何交换两个int型变量的值?String呢?
class BitExer{
public static void main(String[] args){
int m = 10;
int n = 20;
System.out.println("m ="+ m + ",n = " + n);
// 交换两个变量的值
// 方法1:声明一个临时变量(推荐)
int temp = m;
m = n;
n = temp;
System.out.println("m = " + m + ", n = " + n);
// 方法2:使用加减法
// 优点:不需要定义临时变量。
// 缺点:难、适用性差(不适用于非数值类型)、可能超出int的范围
int a = 1 ;
int b = 2;
a = a + b; // a = 3
b = a - b; // b = 1
a = a - b; // a = 2
// 方法3:使用位运算
// 优点: 不需要定义临时变量
// 缺点: 真难、适用性差(不适用于非数值类型)
// m = k ^ n = (m ^ n) ^ n
int a = 1;
int b = 2;
a = a ^ b;
b = a ^ b; // (m ^ n) ^ n ---> m
a = a ^ b;
// 方法4: 使用数组
int[] arr = new int[]{1,2};
arr[0] = arr[0] + arr[1];
arr[1] = arr[0] - arr[1];
arr[0] = arr[0] - arr[1];
int a = arr[0];
int b = arr[1];
// 注意:以上的方法都可以用于基本数据类型,但对于引用数据类型,如类、对象等,需要考虑引用的指向问题。
// 此外,第 3 种方法使用了异或操作符,不适用于浮点数和其他非整型数据类型
// 主要推荐第一种方式:声明一个临时变量
}
}