Java中位运算符的运用

位运算符分为:按位与按位或按位异或左移右移,符号表示分别是:&|^<<>>,在Java或者Android中如果使用位运算符会提高程序的性能,因为位运算符在计算机中的计算速度是非常快的。

在学习位运算之前,首先需要理解补码的概念,在计算机中的数值都是以补码的形式存在的,当计算机中处理数据时,其实就是处理数值的补码

假如一个整数5,它的二进制表示是101,那么它的补码也是101,所以它在计算机中的表示是101

那么,补码该怎么去理解?

计算机中,没有原码反码的概念,之所以引出原码反码的概念,其实是为了简化补码的理解,纵所周知,数值分为无符号数和有符号数,可以理解为正数负数
正数的原码、反码、补码相同;
负数的补码等于原码的反码再加一;

举个例子:

  • 计算5的补码

5是正数,所以不需要计算,正数的原码、反码、补码完全一致;

  • 计算-5的补码

假设-5的数据类型是byte(一个字节)(八位二进制)

-5的原码:10000101(第一位代表符号位)
-5的反码:11111010(符号位不变,剩下的7位取反)
-5的补码:11111011(反码+1,末尾如果是1则逢二进一,如果越界则越界的高位直接舍弃)

所以,-5在计算机中的表示是11111011

11111011取反之后再加一,结果值和-5的原码一致,所以得出结论:补码的补码是原码

假设-5用变量a表示,那么~a等于多少呢?

a前面的破浪符号表示取反的意思,取反就是二进制0变成1,1变成0,包括符号位,a的原码是10000101,那么取反之后就是01111010? 这个答案是错误的,因为原码并不是计算机中的表示,我们需要将原码转成补码之后才能取反,a的补码是11111011,其反码是00000100,所以-5的反码为4。

下面开始举例,看看在实际运用中的艺术吧。

【计算数值的奇偶性】

假设有一个正整数n,要求判断n是奇数还是偶数?

  • 方法一:直接除以2

这个方法是最容易想到的方法,直接除以2就可以判断奇偶性。

如果`(n / 2)`的值为0,则为偶数;
如果`(n / 2)`的值为1,则为奇数;
  • 方法二:使用&运算符
如果`n & 1`的值为0,则为偶数;
如果`n & 1`的值为1,则为奇数;
  • 方法三:使用取模(取余)运算符%
如果`n % 2`的值为0,则为偶数;
如果`n % 2`的值为1,则为奇数;

运算速率比较:方法一 < 方法二 < 方法三

【乘法运算】

假设有一个数n,要求乘以2k

  • 方法一:使用*运算符

    n * 2k

  • 方法二:使用<<运算符
n << k

【除法运算】

假设有一个数n,要求除以2k

  • 方法一:使用/运算符

    n / 2k

  • 方法二:使用<<运算符
n << k

【交换两个数值】

假设有两个数a,b,要求交换这两个数值?

  • 方法一:

定义一个临时区域,int temp;

temp = a;//将a的值放入临时区域
a = b;//将b的值赋值给a
b = temp;//将临时区域的值赋值给b
  • 方法二:采用^运算符

异或(^)的特性:

  • 任意数和自身异或结果为0,0和任意数异或结果还是其本身
  • 符合结合律和交换律

根据异或的特性,可以轻松交换两个变量的值

a ^= b; //相当于 a = a ^ b
b ^= a; //相当于 b = a ^ b
a ^= b;//相当于 a = a ^ b

【用户权限判断】(或者状态叠加的情况)

假设有四种权限,分别是:那么如何去合理的表示用户只有一个权限或多个权限的情况,比如:

  • 我是张三:只有查询权限;
  • 我是李四:有查询、增加、修改权限;
  • 我是王五:有查询、增加、修改、删除权限;

现在讲,四个权限分别用1、2、4、8来表示,那么张三、李四、王五三人的权限用一个整数来表示:

  • 张三:1
  • 李四:1 + 2 +4 = 7
  • 王五:1 + 2 + 4 + 8 = 15;

那么,张三的权限为1,李四的权限为7,王五的权限为15。

那么,重点来了

判断张三是否有查询权限:1 & 1 = 1;
判断张三是否有删除权限:1 & 8 = 0;
判断李四是否有查询权限:7 & 1 = 1;
判断李四是否有增加权限:7 & 2 = 1;
判断李四是否有修改权限:7 & 4 = 1;
判断李四是否有删除权限:7 & 8 = 0;
判断王五是否有删除权限:15 & 8 = 1;
判断王五是否有查询权限:15 & 1 = 1;

1代表拥有权限,0代表没有权限。

【一道经典面试题】

有1000个一模一样的瓶子,其中有 999 瓶是普通的水,有一瓶是毒药。任何喝下毒药的生物都会在一星期之后死亡。现在,你只有 10 只小白鼠和一星期的时间,如何检验出哪个瓶子里有毒药?

这是一道算法题,考官问的是解决思路,通过二分查找来解决。

思路如下:

10只小白鼠,用二进制表示,第一位是第一个白鼠,第二位是第二个白鼠,第三位是第三个白鼠,依次类推...,其中0表示存活,1表示死亡,10只白鼠,代表210=1024种变化,1000个瓶子足够满足需求。

为了便于理解,我将这道题目简化一下,如下:

有8个一模一样的瓶子,有一瓶是毒药。任何喝下毒药的生物都会立即死亡。现在,你只有 3只小白鼠,如何检验出哪个瓶子里有毒药?

现在给8个瓶子标号

(1)第一个瓶子用二进制表示:000
(2)第二个瓶子用二进制表示:001
(3)第三个瓶子用二进制表示:010
(4)第四个瓶子用二进制表示:011
(5)第五个瓶子用二进制表示:100
(6)第六个瓶子用二进制表示:101
(7)第七个瓶子用二进制表示:110
(8)第八个瓶子用二进制表示:111

以上二进制只有三位,这三位从左到右分别代表三只小白鼠,所以:

5、6、7、8瓶水混合起来为第一个样本,给第一个小白鼠喝;
3、4、7、8瓶水混合起来为第二个样本,给第二个小白鼠喝;
2、4、6、8瓶水混合起来为第三个样本,给第三个小白鼠喝;

可能出现的情况有:

(1)如果第一只小白鼠死了,那么2、4、6、8瓶水必然有一瓶有毒;

第一只小白鼠死亡是已知条件,遍历这8个瓶子的编号,与001做&运算,如果结果为1则这瓶水有可能是毒药。

    int k = 1;//假设第一只小白鼠死亡,二进制表示为001

    for(int i=0;i<8;i++){//i为瓶子编号
        int n = i & k;
        if(n == 1){
            //表示当前瓶子可能含有毒药
        }
    }

(2)如果第二个小白鼠死了,那么3、4、7、8瓶水必然有一瓶有毒;

    int k = 2;//假设第二只小白鼠死亡,二进制表示为010

    for(int i=0;i<8;i++){//i为瓶子编号
        int n = i & k;
        if(n == 1){
            //表示当前瓶子可能含有毒药
        }
    }
}

(3)如果第三个小白鼠死了,那么5、6、7、8瓶水必然有一瓶有毒;

    int k = 4;//假设第二只小白鼠死亡,二进制表示为100

    for(int i=0;i<8;i++){//i为瓶子编号
        int n = i & k;
        if(n == 1){
            //表示当前瓶子可能含有毒药
        }
    }

(4)如果一个没死,那么第1瓶有毒;

【用户编号的类型判断】

在2n-1~2n-1范围内的任意两个整数&操作的结果都是两数最小的那个数,不在这个范围内的&操作都是0。(n>=1)

  • 当n=1时,范围是1~1
  • 当n=2时,范围是2~3
  • 当n=3时,范围是4~7
  • 当n=4时,范围是8~15
  • 当n=5时,范围是16~31
  • 当n=6时,范围是32~63
  • 当n=7时,范围是64~127
  • 当n=8时,范围是128~255
  • 当n=9时,范围是256~511
  • 当n=10时,范围是512~1023
  • 当n=11时,范围是1024~2047
  • 当n=12时,范围是2048~4095
  • 当n=13时,范围是4096~8191
  • 当n=14时,范围是8192~16383
  • 当n=15时,范围是16384~32767
  • 当n=16时,范围是32768~65535
  • 当n=17时,范围是65536~131071
  • 当n=18时,范围是131072~262143
  • 当n=19时,范围是262144~524287
  • 当n=20时,范围是524288~1048575
    依次类推...

我所知道的应用场景:
(1)一个算法不仅能生成账户的useid,还能给userid分类,比如:教授账户、老师账户、学生账户,分别对应n=18,n=19,n=20,也就是说教授userid取值范围是131072--262143,老师userid的取值范围是262144--524287,学生userid的取值范围是524288--1048575,这里假设是范围A,范围B和范围C,接下来是重点:
取同一个范围中的任意两个数做位运算&操作,计算出来的值总是两数中的最小值;
取不同范围中的任意两个数做位运算&操作,计算出来的值总是0;

由于计算机默认把0当做false,把大于0的数当做true,所以这个算法在此场景下的作用有以下几点:

1.可以作为userid的使用;
2.可以将userid分类,并且可以用&运算符求出两个userid是否是同类,当前userid是否是教授,当前userid是否是老师,当前userid是否是学生。

(2)可以用作状态分类,取该算法的任意几个范围,每个范围都有一系列不同的数字。
每个范围可以被当做一种状态,每个状态又分为好几种小状态,这种尝尽用该算法还是比较方便的。

[状态添加和移除]

现有以下几种状态(状态不能为0,且是2次幂)

    int STATUS_1 = 1 << 0;
    int STATUS_2 = 1 << 1;
    int STATUS_3 = 1 << 2;
    int STATUS_4 = 1 << 3;
    int STATUS_5 = 1 << 4;

使用按位或添加状态,如:

 flag |= STATUS_1
 flag |= STATUS_2
 flag |= STATUS_3
 flag |= STATUS_4

使用按位与和按位非移除状态,如:

flag &= ~STATUS_1
flag &= ~STATUS_2
flag &= ~STATUS_3
flag &= ~STATUS_4

判断是否有这个状态,如:

a = flag & STATUS_1

如果a > 0,则flag有STATUS_1这个状态(其实a = STATUS_1)
如果a=0,则flag没有STATUS_1这个状态

[本章完...]

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 157,298评论 4 360
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 66,701评论 1 290
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 107,078评论 0 237
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,687评论 0 202
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,018评论 3 286
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,410评论 1 211
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,729评论 2 310
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,412评论 0 194
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,124评论 1 239
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,379评论 2 242
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,903评论 1 257
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,268评论 2 251
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,894评论 3 233
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,014评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,770评论 0 192
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,435评论 2 269
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,312评论 2 260

推荐阅读更多精彩内容

  • 「WTF系列」深入Java中的位操作 关于WTF系列 引 学完本章节你将学会位的基础概念与语法,并且还会一些骚操作...
    qiujuer阅读 825评论 0 5
  • 进制基本概念 什么是进制?进制是一种计数的方式,数值的表示形式 常见的进制十进制、二进制、八进制、十六进制 进制书...
    极客江南阅读 1,942评论 0 11
  • 原码 原码是电脑运算的名词,是指“未经更改”的码。为了便于ALU(算术逻辑单元)的设计,又发展出反码、补码等转换过...
    __RY__阅读 5,804评论 0 2
  • 概述 在学习位运算之前,先说下几个概念: 机器数:一个数字在计算机中的二进制表达形式就叫做机器数。机器数是有符号位...
    骑着乌龟去看海阅读 2,402评论 1 4
  • 为什么你的经济独立会吸引到优秀的男人, 一个男人如果看到你很上进,致力于实现自己的梦想,并且不断进取,他就会感觉到...
    美人鱼_86阅读 145评论 0 0