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();
    }
}
posted @ 2023-01-03 15:38  如此而已~~~  阅读(37)  评论(0编辑  收藏  举报