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();
}
}
标签:11111111,arr,Java,运算,33,System,00000000,int,out
From: https://www.cnblogs.com/fragmentary/p/17022428.html