• Java中的位运算符、移位运算符


    1 概述

    Java中的位运算符有:&(与)、|(或)、^(异或)、~(取反)。
    移位运算符有:<<(左移)、>>(右移)、>>>(无符号右移),没有<<<运算符。

    2 位运算符

    计算口诀

    运算 规则
    & 全1为1
    | 有1为1
    ^ 相异为1
    ~ 全部取反

    2.1 $(与)

    有0为0,全1为1

    2.2 |(或)

    有1为1,全0为0

    2.3 ^(异或)

    相同为0,相异为1

    2.4 ~(非)

    0变1,1变0

    3 移位运算

    在阅读源码的过程中,经常会看到这些符号<< ,>>,>>>,这些符号在Java中叫移位运算符,在写代码的过程中,虽然我们基本上不会去写这些符号,但需要明白这些符号的运算原理,比如HashMap中有以下代码:

    static final int DEFAULT_INITIAL_CAPACITY = 1 << 4;//1左移4位为16
    static final int MAXIMUM_CAPACITY = 1 << 30;//1左移30位为1073741824
    static final int hash(Object key) {
         int h;
         return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);//无符号右移
    }
    

    上段代码中就包含左移运算符<<,无符号右移运算符>>>。

    接下来我们以Java中的int类型为例介绍三种移位运算符。
    首先定义int类型的变量a,b

    int a = 0B00101100_01010011_01101000_11010110; //十进制743663830
    int b = 0B10101100_01010011_01101000_11010110; //十进制-1403819818
    

    3.1 左移运算符:<<

    左移运算符<<的操作是舍弃高位,低位补0.
    如图是int类型a在左移1位和2位后的结果。

    可以看到左移1位的值是原始值的两倍,所以可以用左移代理乘2的倍数运算。但是如果左移后的值超出了类型的最大值,结果就不可预知了,可能会变成负数,也可能比原来的值小。如图,变量a在左移两位后最高位变为了1,值就变为了负值。

    程序中的写法:

    public class TestDemo {
        public static void main(String[] args) {
            int b = 0B10101100_01010011_01101000_11010110;
            int a = 0B00101100_01010011_01101000_11010110;
            System.out.println("a的原始十进制:	"+a);
            System.out.println("a的原始二进制:	"+getBinaryString(a));
            System.out.println("a的左移1位二进制:	"+getBinaryString(a<<1));
            System.out.println("a的左移1位十进制:	"+getInt(getBinaryString(a<<1)));
            System.out.println("a的左移2位二进制:	"+getBinaryString(a<<2));
            System.out.println("a的左移2位十进制:	"+getInt(getBinaryString(a<<2)));
    
        }
    
        static String getBinaryString(int a){
            String binaryString = Integer.toBinaryString(a);//转成二进制
            String zeroString = "";//补缺少的0
            for (int i=0;i<32 - binaryString.length();i++){
                zeroString += "0";
            }
            binaryString = zeroString + binaryString; //补上0的二进制
            String regex = "(.{8})";
            binaryString = binaryString.replaceAll(regex,"$1_");
            binaryString = binaryString.substring(0,binaryString.length() - 1);
            return binaryString;
        }
    
        static int getInt(String a ){
            a = a.replace("_","");
            char first = a.charAt(0);
            a = a.substring(1);
            int value = Integer.parseInt(a,2);
            return first == '0' ? value:-value;
        }
    }
    
    a的原始十进制:   743663830
    a的原始二进制:   00101100_01010011_01101000_11010110
    a的左移1位二进制:01011000_10100110_11010001_10101100
    a的左移1位十进制:1487327660
    a的左移2位二进制:10110001_01001101_10100011_01011000
    a的左移2位十进制:-827171672
    

    如果移动的位数大于等于类型本身的位数,会对移动的位数求余后再移动。
    如 a<<40,是左移40位,大于int类型的32位,实际应该左移40%32=8位。

    System.out.println("a左移8位:	"+(a<<8));
    System.out.println("a左移40位:	"+(a<<40));
    
    a左移8位:	1399379456
    a左移40位:	1399379456
    

    可以看到左移8位和左移40位,结果是相同的。

    由于double,float在二进制中的表现比较特殊,因此不能来进行移位操作,报错,编译不过,如下图:

    注意:其它几种整形byte,short移位前会先转换为int类型(32位)再进行移位,这里就不写代码测试了,大家有兴趣可自行测试。

    3.2 右移运算符:>>

    左移运算符>>的操作是舍弃低位,高位补符号位.
    如图是int类型a在右移1位和2位后的结果。

    可以看到右移1位的值是原始值的1/2,所以可以用右移代替除2运算。和左移一样,int类型移位大于等于32位时,long类型大于等于64位时,会先做求余处理再位移处理,byte,short移位前会先转换为int类型(32位)再进行移位。以上是正数的位移,我们再来看看负数的右移运算,如图,

    综上所述:右移运算符>>的运算规则也很简单,丢弃右边指定位数,左边补上符号位。

    3.3 无符号右移运算符:>>>

    无符号右移运算符>>>和右移运算符>>是一样的,只不过右移时左边是补上符号位,而无符号右移运算符是补上0,也就是说,对于正数移位来说等同于:>>,负数通过此移位运算符能移位成正数。

    无符号右移运算符>>的运算规则也很简单,丢弃右边指定位数,左边补上0。

    参考:Java中的移位运算符

    --------------- 我每一次回头,都感觉自己不够努力,所以我不再回头。 ---------------
  • 相关阅读:
    2020/5/8
    2020/5/8
    2020/5/6
    2020/4/30
    2020/4/29
    2020/4/28
    2020/4/27
    KMP算法详解
    博客搬家声明
    洛谷P2831 NOIP2016 愤怒的小鸟
  • 原文地址:https://www.cnblogs.com/zjw-blog/p/13807940.html
Copyright © 2020-2023  润新知