33_Java中的位运算
Java中的位运算符
一、位运算概述
位运算就是直接对整数在内存中的二进制位进行操作
分类:
逻辑位运算符:位与(&)、位或(|)、位异(^)、位取反(~)
移位运算:左移(<<)、右移(>>)、无符号右移(>>>)
逻辑位运算:
前面使用逻辑运算符时,两边跟的是boolean表达式,现在是数字(计算时会将其转换为二进制按位进行运算)
符号 | 作用 | 范例 | 运算规则 |
---|---|---|---|
& | 位与 | 3 & 4 | 同1为1,其余为0 |
| | 位或 | 3 | 4 | 同0为0,其余为1 |
^ | 位异或 | 3 ^ 4 | 相同为0,不同为1 |
~ | 位取反 | ~3 | 0变1,1变0 |
参考代码:
package com.itheima; /* 逻辑位运算符: 位与(&) 同1为1,其余为0 位或(|) 同0为0,其余为1 位异(^) 相同为0,不同为1 位取反(~) 0变1,1变0 */ public class OperatorDemo01 { public static void main(String[] args){ //位与(&) 同1为1,其余为0 System.out.println(3 & 4); /* 3的二进制为:11 -->00000000 00000000 00000000 00000011(默认为整型4字节,32位) 4的二进制为:100 -->00000000 00000000 00000000 00000100 正数:原码、反码、补码相同 00000000 00000000 00000000 00000011 & 00000000 00000000 00000000 00000100 -------------------------------------- 00000000 00000000 00000000 00000000 */ //位或(||) 同0为0,其余为1 System.out.println(3 | 4); /* 00000000 00000000 00000000 00000011 & 00000000 00000000 00000000 00000100 -------------------------------------- 00000000 00000000 00000000 00000111 */ //位异(^) 相同为0,不同为1 System.out.println(3 ^ 4); /* 00000000 00000000 00000000 00000011 & 00000000 00000000 00000000 00000100 -------------------------------------- 00000000 00000000 00000000 00000111 */ //位取反(~) 0变1,1变0 System.out.println(~3); /* ~ 00000000 00000000 00000000 00000011 -------------------------------------- 11111111 11111111 11111111 11111100 最高位为1,是负数 补码为:1 1111111 11111111 11111111 11111100 反码为:1 1111111 11111111 11111111 11111011 在补码基础上:符号位不变、减一 原码为:1 0000000 00000000 00000000 00000100 在反码基础上:符号位不变、按位取反 */ } }
移位运算符:
符号 | 作用 | 范例 | 运算规则 |
---|---|---|---|
<< | 左移 | 3 << 2 | 高位丢弃,低位补0 |
>> | 右移 | 24 >> 2 | 正数左补0,负数左补1 |
>>> | 无符号右移 | 24 >>> 2 | 无论该数为正还是为负,右移之后左补0 |
参考代码:
package com.itheima; /* 移位运算符: 左移(<<):高位丢弃,低位补0 右移(>>):正数左补0,负数左补1 无符号右移(>>>):无论该数为正还是为负,右移之后左补0 */ public class OperatorDemo02 { public static void main(String[] args){ //左移(<<):高位丢弃,低位补0 System.out.println(3 << 2); //3 * (2 ^ 2) = 3 * 4 = 12 /* 3的二进制数据:00000000 00000000 00000000 00000011 正数的原码、反码、补码都是一样的 左移: 00000000 00000000 00000000 00000011 00000000 00000000 00000000 0000001100 移动后: 00000000 00000000 00000000 00001100 相当于:原数字 * 进制数^移动位数 */ //右移(>>):正数左补0,负数左补1 System.out.println(24 >> 2); //24 / (2 ^ 2) = 24 / 4 = 4 /* 24的二进制数据:00000000 00000000 00000000 00011000 可以在cmd中输入calc,打开计算机进行查看 右移: 00000000 00000000 00000000 00011000 0000000000 00000000 00000000 00011000 移动后: 00000000 00000000 00000000 00000110 */ //无符号右移(>>>):无论该数为正还是为负,右移之后左补0 System.out.println(24 >>> 2); //使用负数查看 右移 与 无符号右移的区别 System.out.println(-24 >> 2); /* -24的二进制数据:10000000 00000000 00000000 00011000 对应的反码是:11111111 11111111 11111111 11100111 对应的补码是:11111111 11111111 11111111 11101000 右移: 11111111 11111111 11111111 11101000 1111111111 11111111 11111111 11101000 移动后的补码结果:11111111 11111111 11111111 11111010 对应的反码:11111111 11111111 11111111 1111001 对应的补码:10000000 00000000 00000000 0000110 */ System.out.println(-24 >>> 2); /* -24的二进制数据:10000000 00000000 00000000 00011000 对应的反码是:11111111 11111111 11111111 11100111 对应的补码是:11111111 11111111 11111111 11101000 无符号右移: 11111111 11111111 11111111 11101000 0011111111 11111111 11111111 11101000 移动后的补码: 0011111111 11111111 11111111 111010 根据符号位为0,是正数,所以原、反、补码一致 */ } }
练习
练习1参考代码:
package com.itheima; /* 乘法运算: 请用最有效率的方式写出计算2 * 8 的结果 判断奇偶 判断一个数据是否是偶数 */ public class OperatorTest01 { public static void main(String[] args){ //请用最有效率的方式写出计算2 * 8 的结果 System.out.println(2 << 3); //2 * 2 ^ 3 //判断一个数据是否是偶数 int a = 10; a = 9; /*if(a % 2 == 0){ System.out.println("是偶数"); }*/ /* 10的二进制数:00000000 00000000 00000000 00001010 00000000 00000000 00000000 00001010 & 00000000 00000000 00000000 00000001 -------------------------------------- 00000000 00000000 00000000 00000000 整型十进制的 1 转换为二进制时,前面31位补0,根据位与运算前面都为0,就看最后一位是否为1 除去末尾位数以外的位数都是2的倍数所以可以整除 */ if((a & 1) == 0){ System.out.println("是偶数"); } } }
练习2参考代码:
package com.itheima; /* 题目:两个变量的交换 需求1:交换变量a和变量b的值 需求2:交换变量a和变量b的值,不能使用第三方变量 */ public class OperatorTest02 { public static void main(String[] args) { int a = 10; int b = 20; System.out.println("交换前 a:" + a + ",b:" + b); /*//需求1:交换变量a和变量b的值 int temp = a; a = b; b = temp;*/ //需求2:交换变量a和变量b的值,不能使用第三方变量 a = a ^ b; //a = a ^ b b = a ^ b; //b = a ^ b = a ^ b ^ b = a a = a ^ b; //a = a ^ b = a ^ b ^ a = b System.out.println("交换后 a:" + a + ",b:" + b); System.out.println(3 ^ 5 ^ 5 ^ 3 ^ 8); /* 3的二进制数据: 00000000 00000000 00000000 00000011 4的二进制数据: 00000000 00000000 00000000 00000100 两个相同的数据做异或为0 00000000 00000000 00000000 00000100 ^ 00000000 00000000 00000000 00000100 -------------------------------------- 00000000 00000000 00000000 00000000 任意一个数据和0做异或还是数据本身 00000000 00000000 00000000 00000011 ^ 00000000 00000000 00000000 00000000 -------------------------------------- 00000000 00000000 00000000 00000011 */ } }
练习3参考代码:
package com.itheima; import java.util.Random; /* 题目: 现有0到99,共计100个整数,各不相同,将这个整数放入一个数组中。 然后,在这个数组中添加一个0~99的任意一个整数数字(唯一重复的数字),把这101个数据打乱 需求: 将这个重复数字找出来 */ public class OperatorTest03 { public static void main(String[] args){ //定义一个长度为100的int类型数组 int[] arr = new int[101]; //现有0到99,共计100个整数,各不相同,将这100各数据放入一个数组中 for(int i = 0; i < 100; i++){ arr[i] = i; } //在索引100的位置,添加一个重复元素 // arr[100] = 88; //练习:把这里面的数据修改为随机数实现 Random r = new Random(); arr[100] = r.nextInt(100); //遍历一下 System.out.println("数据打乱前:"); printArray(arr); //打乱数据 Random r2 = new Random(); for(int x = 0; x < 1000; x++){ int i = r.nextInt(101); int j = r.nextInt(101); //交换数组中i 和 j 位置的元素 int temp = arr[i]; arr[i] = arr[j]; arr[j] = temp; } System.out.println("数据打乱后:"); printArray(arr); //方式1:初学者的想法 // itheima:for(int x = 0; x < arr.length; x++){ // for(int y = x + 1; y < arr.length; y++){ // if(arr[x] == arr[y]){ // System.out.println("这个重复元素是:" + arr[x]); // break itheima; //找到数据时,退出此标签代表的代码 // } // } // } //方式2:巧妙的方法 // //首先,把数组中的所有元素累加起来 // int sum = 0; // for(int x = 0; x < arr.length; x++){ // sum += arr[x]; // } // // //接着,拿到求和结果减去0~99相加,最后剩余的数据就是重复的唯一数据 // for(int x = 0; x < 100; x++){ // sum -= x; // } // // System.out.println("这个重复数据是:" + sum); //方式3:异或运算符 /* 分析: 先将所有数据异或一遍,此时重复数据会抵消为0 再将范围内的所有数据异或一次,这样原本没有重复的数据就会抵消为0 最后就只剩下进行三次异或的那个原本的重复数据 简单示例: 数组:1 2 3 4 1 所有数据进行异或:arr[0] = 1 ^ 2 ^ 3 ^ 4 ^ 1 = 2 ^ 3 ^ 4 ^ 0 = 2 ^ 3 ^ 4 arr[0] ^ 1 ^ 2 ^ 3 ^ 4 = 2 ^ 3 ^ 4 ^ 1 ^ 2 ^ 3 ^ 4 = 1 即得出原本的重复数据 */ for(int x = 1; x < arr.length; x++){ arr[0] ^= arr[x]; } for(int x = 0; x < 100; x++){ arr[0] ^= x; } System.out.println("这个重复数据是:" + arr[0]); } private static void printArray(int[] arr) { int count = 0; for(int i = 0; i < arr.length; i++){ System.out.print(arr[i] + "\t"); if(++count % 10 == 0){ System.out.println(); } } System.out.println(); } }
本文作者:编程初学者求大佬指点
本文链接:https://www.cnblogs.com/fragmentary/p/17022428.html
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步