按位与&或 您所在的位置:网站首页 二进制的按位运算 按位与&或

按位与&或

2024-07-18 00:59| 来源: 网络整理| 查看: 265

一直觉得位运算(与&、或|、非~、异或^、左移)比较深奥,平时也很少接触到,但最近项目又遇到了与位运算相关的“组合属性”用法,有必要学习掌握了。

组合属性

我不知道“组合属性”正确叫法是什么,拿例子说吧。

例子一:Android中的布局文件有这种用法:

上述布局为按钮的layout_gravity属性指定了两个值“bottom”和“center_horizontal”,这两个属性同时生效,效果是按钮会位于父容器底部的水平方向中央。

例子二:android用于安装apk的系统api:(有更简单的例子,只是项目中遇到这个而已)

// @SystemApi public abstract void installPackage( Uri packageURI, IPackageInstallObserver observer, int flags, String installerPackageName);

第三个int参数flags用于设置安装方式的组合值,可以是以下值的组合:

public static final int INSTALL_FORWARD_LOCK = 0x00000001;//受限应用 public static final int INSTALL_REPLACE_EXISTING = 0x00000002;//覆盖安装 public static final int INSTALL_ALLOW_TEST = 0x00000004;//允许测试包 public static final int INSTALL_EXTERNAL = 0x00000008;//安装在外部SD卡 public static final int INSTALL_INTERNAL = 0x00000010;//安装在内置SD卡 ...

用法如:

int i = INSTALL_REPLACE_EXISTING | INSTALL_EXTERNAL;//覆盖安装,装于外部SD卡 mPackageManager.installPackage(uri, observer, i, null);

为什么一个int值就可以表示多个属性呢?这就要归功于位运算的巧妙实现了。

位运算

位运算介绍可见 按位与、或、异或等运算方法,简单明了例子也好。这里摘录组合属性使用的与&或|操作:

按位或 |

运算: 参加运算的两个数,按二进制位进行“或”运算。同位上只要有一个为1,则结果值的该位为1,否则为0。 如,3 | 5 = 7 的运算过程如下:

3 : 0000 0011 5 : 0000 0101 -------------- |运算 7 : 0000 0111

作用:常用来对一个数据的某些位置为1。(类比:打开多个开关) 方法:找到一个数,对应X要置1的位,该数的对应位为1,其余位为零。此数与X相或可使X中的某些位置1。 例:将X=1010 0000的低4位置1 ,用 X | 0000 1111 = 1010 1111即可得到。

按位与 &

参加运算的两个数,按二进制位进行“与”运算。同位上同时为1时,结果值的该位为1,否则为0。 如,3 & 5 = 1 的运算过程如下:

3 : 0000 0011 5 : 0000 0101 -------------- &运算 1 : 0000 0001

作用:常用来判断一个数中指定位是否为1。(类比:检测某个开关是否打开) 方法:找一个数,对应X要取的位,该数的对应位为1,其余位为零,此数与X进行“与运算”可以得到X中的指定位。 例:设X=10101110, 取X的低4位,用 X & 0000 1111 = 0000 1110 即可得到; 如果要判断X的第三位是否为1,用 X & 0000 0100 = 0000 0100 ,即可知道第三位为1。

组合属性的实现 原理

组合属性的实现,就是巧妙地使用了按位或|、按位与&。 首先,将多个属性设置为不冲突的二进制数,如:

// 十进制 二进制 十六进制 int A = 1; //0000 0001 0x0001 int B = 2; //0000 0010 0x0002 int C = 4; //0000 0100 0x0004 int D = 8; //0000 1000 0x0008 int E =16; //0001 0000 0x0010 //(复习一下,Java7中可以用0b表示二进制数,如int D = 0b00001000,更直观)

设置组合属性时,用按位或|运算为一个整数结果result,像是打开了多个开关。如:

int result = A | C;// A|C = 0001|0100 = 0101, 即 A|C = 1|4 = 5

读取组合属性时,将结果result与特定属性二进制数做按位与&运算,若结算结果与该属性相等,说明该属性开关被打开了。如:

if ((result & A) == A) { // result & A = 0101&0001 = 0001, 即 result&A = A // A属性生效 } if ((result & B) == B) { // result & B = 0101&0010 = 0000 != 0010, 即 result&B != B // B属性不生效 } if ((result & C) == C) { // result & C = 0101&0100 = 0100, 即 result&C = C // C属性生效 } 注意

位运算按二进制进行,虽然并不要求参与运算的数表示为二进制,但应用常量方式定义和使用组合属性,并注释二进制以便理解。 如,以上代码用十进制表示,等价为:

int result = 1 | 3; if ((result & 1) == 1) { // A属性生效 }

虽然等价,但我认为这种魔数(magic number)更难以理解组合属性的原理。如我在公司代码中看到一段:

int i = 16777216;//w t f? 原来是十六进制0x‭1000000‬,‭二进制0001000000000000000000000000‬ i |= 2; mPackageManager.installPackage(uri, observer, i, null); DEMO package com.kwws.demo; public class CombineParam { private static final int A = 1;// 0000 0001 private static final int B = 2;// 0000 0010 private static final int C = 4;// 0000 0100 private static final int D = 8;// 0000 1000 private static final int E = 16;//0001 0000 public static void main(String[] args) { int result = A | C | E; echo("result:%d(%s)", result, Integer.toBinaryString(result)); if ((result & A) == A) { echo("A works."); } if ((result & B) == B) { echo("B works."); } if ((result & C) == C) { echo("C works."); } if ((result & D) == D) { echo("D works."); } if ((result & E) == E) { echo("E works."); } } private static void echo(String format, Object... args) { System.out.println(String.format(format, args)); } private static void echo(String str) { System.out.println(str); } }

结果:

result:21(10101) A works. C works. E works.

参考 按位与、或、异或等运算方法


【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有