彻底搞清楚java中的移位运算

目录

1、左移<<(不分有符号和无符号,这一点与右移不同)

2、右移:分为带符号右移>>和不带符号右移>>>

3、相关面试题让你更加融会贯通


1、左移<<(不分有符号和无符号,这一点与右移不同)


要点1:忽略左边任何位包括符号位置,右边补0;例如,1往左移动31位,则符号位变为1,于是变成了int中最小的负整数;
要点2:如果移动的位数超过了int的最大可移动位数31位,那么编译器会对移动的位数取模。如对int型移动33位,实际上只移动了33%32=1位。
要点3:当移动前后移动后取值都在有效值范围内时,左移动一位相当于值*2,右移动一位相当于除以2(即左右移动的时候没有丢失有效位1的前提下成立)。很多地方没有加上最前面这个条件,导致很多学员一头雾水(举出了一堆反例,比如3左移30位得到-1073741824);
1)打印1的所有二进制位
System.out.println(printBit(1));
00000000000000000000000000000001
2)打印1左移31位后的所有二进制位和10进制数值;
System.out.println(printBit(1<<31));
10000000000000000000000000000000
System.out.println(1<<31);
-2147483648
2)打印1左移32位后的所有二进制位和10进制数值;
System.out.println(printBit(1<<32));
System.out.println(1<<32);
00000000000000000000000000000001
1
3)打印1左移33位后的所有二进制位和10进制数值;
System.out.println(printBit(1<<33));
System.out.println(1<<33);
00000000000000000000000000000010
4)如果是负数,是否也满足左移动乘2的规律,这里做一下细细的分析;
首先找一个左边第二位非0的负数(如果左边第二位是0,那么这个负数(取反+1)*2的绝对值超出了负数的绝对值范围);假设整数只有8位,例子如下:

从上面可以看出,只要负数在取值范围内,仍然满足左移一位等于值*2的规律;

2、右移:分为带符号右移>>和不带符号右移>>>

1)带符号右移>>:右移之后,左边的补上符号位,正数补0,负数补1

2)无符号右移位>>>,不管正数还是负数,高位都用0补齐(忽略符号位);

3)举例如下:
System.out.println(printBit(Integer.MIN_VALUE));
System.out.println(printBit(Integer.MIN_VALUE>>1));
System.out.println(printBit(Integer.MIN_VALUE>>>1));
System.out.println(Integer.MIN_VALUE);
System.out.println(Integer.MIN_VALUE>>1);
System.out.println(Integer.MIN_VALUE>>>1);
Integer.MIN_VALUE:        10000000000000000000000000000000
Integer.MIN_VALUE>>1:  11000000000000000000000000000000
Integer.MIN_VALUE>>>1:01000000000000000000000000000000
Integer.MIN_VALUE:-2147483648
Integer.MIN_VALUE>>1:-1073741824
Integer.MIN_VALUE>>>1:1073741824
=================================

4)同样的道理,右移动相当于除以2,也是不能超出数据类型的范围才成立;

3、相关面试题让你更加融会贯通


1)统计二进制中1的个数
解法1:
public static int getBitCount1(int num){
        int count  = 0;
        for(int i=31;i>=0;i--){
            
            if((num>>i & 1) == 1){
                count++;
            }
            
        }
        return count;
    }
解法2:
public static int getBitCount2(int num){
        int count  = 0;
        for(int i=31;i>=0;i--){
            
            if((1< 0){
                count++;
            }
            
        }
        return count;
    }
分析:以上两个解法中,解法2是有问题的,当num为负数时,1左移31位后与num位与后为10000000...,是负数不大于0;应该改为:if((1<

2)判断输入整数是否为2的幂


解法1:
public static boolean ifTwoPow(int num){
        
        boolean flag  = true;
        
        while(num!=1){
            
            if(num<=0 || num%2!=0){
                flag =  false;
                break;
            }
            
            num=num>>1;
        }
        
        return flag;
        
    }
解法2:
public static boolean ifTwoPow2(int num){
        //解释:与运算为0,说明最高位的1变为了0,最高位的1因为减去1的操作都被拿来用了,说明后面全是0不够减,哈哈机智如我
        return (num & (num-1)) == 0;
        
    }

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Hiker帝国

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值