运算符巧用
看源码是每个程序员必过的坎儿,刚开始看源码真的太痛苦了….没办法,只有不断的看源码才能了解一些原理,才能快速的进步。在源码的过程中你坑定遇到过这样位运算那样位运算,当位运算你肯定清除,但是运算符一组合,就懵了。。。。什么鬼,反正我就是这样,就是知识我们不熟悉其中运算的效果而已。
计算机中是以补码的形式保存所有整数的
负数:源码除最高符号位,其余为按位取反得到反码,反码+1得到补码
正数:源码和补码相同
补码—>源码:补码-1=得到反码,发码出最高符号位,其余为取反得到原码
(>>):有移,(X>>Y)X为int类型,X转化为32位的二进制,如果为正数,左边空位用0补位,如果为负数,用1补位;相当于X除以2的y方
(>>>)(无符号有移):都用0 补位
- <<:移动后,右边有0补位;相当于X乘以2的Y方
关于移位运算符>>、<<、>>>并不是适合所有数值类型,只适合byte、short、char、int、long等整数类型进行运算;
总结:
1. 一个32位的int整数,右移(b>>a),当a>32时,系统用b%32得到结果才是移位的位数。例如:a>>33和a>>1结果是一样的(因为int类型只有32位),a>>32还是a本身。
2. 一个64位的long整数,右移(b>>a),当a>64时,系统用b%64得到结果才是移位的位数。例如:a>>64和a>>1结果是一样的,a>>64还是a本身。
2. 对于低于int类型的操作数(如byte、short、char)总是会自动转化为int在移位
^(异或)
相同为0,不同为1
1 1—>0
0 0—>0
1 0—>1
0 1—>1
特定位取反
最后一位取反:X^1(高位不变(位与0异或不变))
0111
^ 0001
---------------
0110
对异或取反,叫做(同或)或者(异或非)
巧用技巧
奇偶数判断
0101
& 0001
--------------
0000
利用最有一位是否是1,判断是否是奇数;为1,就是奇数;为0就是偶数;
X&1=1,表示X为奇数
X&1=0,表示X为偶数
不用temp交换两个数
X=5,y=4
X^=y;
y^=X;
X^=y
即可交换X、y的值;
特定位取反
使特定位的值取反 (mask中特定位置1,其它位为0 s=s^mask),源源操作数异或操作即可
右数第k位取反:x ^ (1 < < (k-1))
取模运算转化为位运算
X%(2^n)<====>X&((2^n)-1)
清除特定位
源操作数X与掩码mask(特定位为0 其他位都为1)&
举例说明:这里我们要将5(0101)的第三位清除,mask=1011
0101
&
1011
--------------
0001
总结一下公式:X&((1<
取特定位
同样是源操作数和mask(只不过这里特定位为1,其他位为0)与;就不在举例说明,可以参看后面的取出指定位部分
将int型变量a的右起的第k位置1
a=a|(1 <<(k-1))
把右数第k位变成0
x & ~ (1 < < (k-1))
求两个整数的平均值
(X+Y)+((X+Y)>>1)
判断一个整数是不是2的幂(是不是2的n次方(n=0,1…..))
(x&(x-1)==0)&&(X!=0)
——(Android运用)—-
使用位运算来表示共同具有哪些属性,对应为为1就表示具有该属性,为0就表示不具有该属性;
举个例子:
0x01(0001)表示可读
0x02(0010)可写
0x03(0011)表示可读可写
a&~b: 清除标志位b;
a|b: 添加标志位b;
a&b: 取出标志位b;
a^b: 取出a与b的不同部分;
Android中对flag主要由三种操作
- 通过“|”运算向flag变量中增加某个Flag;
原因: 如果flag变量没有XXX_FLAG,则 | 完后flag对应的位为1,如果有XXX_FLAG,则 | 完后值不会变对应位还是1.
flag|=XX_Flag;
通过“&”判断flag变量中是否包含XX_Flag
flag & XXX_FLAG != 0 或者 flag & XXX_FLAG = XXX_FLAG
原因: 如果flag变量里包含XXX_FLAG,则&完后flag变量对应的位为1,因为XXX_FLAG的定义保证了只有一位非0,其他位都为0,所以如果是包含的话&运算后值不为0,值为此XXX_FLAG的值,不包含的话值为0.
flag&XX_Flag:得到的就是XX_Flag标志位的值即取出XX_Flag标志位;举例说明:
0011(可读可写) 0001
& 0010(可写) & 0010
--------------- ---------------
0010(可写) 0010
可以看见取出对应的标志位状态,之前是改为是什么状态(是否是可写状态),与对应位掩码&后,就可以得到该标志位的状态。
Android中应用:
// 返回是否可点击
return (((viewFlags & CLICKABLE) == CLICKABLE ||
(viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE));
3. 取消属性( 取消flag变量中XX_flag)
flag&=~XX_flag;
原因:先对XXX_FLAG进行取反 则XXX_FLAG原来非0的那一位变为0,则使用&运算符后flag变量非0的那一位变为0,则意味着flag变量不包含XXX_FLAG
4. 标志位取反(比如之前是可读不可写状态0001,和掩码0011一异或,对应位(读、写标志位)的标志位都置反了,变成了0010(可写不可读了))
0001
^ 0011
-----------------
0010
Android中运用:
……
private static final int PRESSED = 0x00004000;
int mPrivateFlags ;
……
public void setPressed(boolean pressed) {
if (pressed) {
mPrivateFlags |= PRESSED; // 添加PRESSED状态
} else {
mPrivateFlags &= ~PRESSED; // 取消PRESSED状态
}
refreshDrawableState();
dispatchSetPressed(pressed);
}
- 获取X指定低N位的集合
举例说明:获取233的第6位
11,101001
&
00,111111
--------------------------
00,101001
可以推导出公式就是:X&(N<<k)-1
获取X高N位:
x & (((1 << n) - 1) << (sizeof(x)-n))
sizeof(X):表示X的位数,比如这里是8位