为了加深记忆,还是在上面博客基础上细节处加了点补充,方便时间久了回忆
Okio高性能IO的关键在三点:
2)Buffer中缓存了一个Segment双向闭合链表,用空间换时间嘛。且有大量位运算,把写入的数据通过位运算转换成字节写入缓存,提高了性能。
3)ByteString封装大量api,把各种输入(字符串/...)转成字节数组,封装成新的ByteString返回。
所以学习Buffer前,先复习下位运算
------------------------
1、基础
正数的反码和补码就是正数本身
负数的反码是除了符号位,其他位都取反
负数的补码是负数的反码加1
一个数进行位运算的时候,是在这个数的补码上进行的,正数的补码是原码,负数的补码为原码【除了最高位的符号位】,取反,然后加1。
2、位运算规则
1) & 按位与
只有两个操作数对应位都是1时结果为1,其余为0
负数的&按位与运算,先算出负数的补码,再用补码做按位与运算,再根据结果的补码算出补码的原码
负数根据补码求原码,和根据原码求补码正好相反,先补码减1,【除了符号位】,其他位按位取反
2) |按位或
只要两个操作数对应位有一个是1结果就为1,只有对应位两个都是0结果才为0
3) ~ 按位非
操作数每个位置都去反,原来是0的变成1,原来是1的变成0
4) ^ 按位异或
两个操作数对应位的值不同时结果为1,相同时结果为0
5) << 左位移【符号位不变】
a:符号位不变,低位补0。比如2<<2,就是00000010(这就是2),左位移两个位置变成00001000(值是8)
b:左位移是整个数左位移,右边最低的两位空出来后,低位补0,补了两个0,最左边两个数因为左移溢出两位,直接截断。
c:当移动的位数超过数字本身的位数时,在真正执行位移前,其对要移动的位数做了一些预处理,比如32处理为0,-1处理为31
6) >> 右位移【符号位不变】
a:低位溢出,符号位不变,并用符号位补溢出的高位。
b:右边是低位,操作数向右位移后,低位溢出的部分截断,符号位不变,
最左边(按32位的最左边)高位右移空出的位置用符号位补全
7) >>> 无符号右移
低位溢出,高位补0。注意,无符号右移(>>>)中的符号位(最高位)也跟着变,
无符号的意思是将符号位当作数字位看待
一些规则:
1) 位运算的操作数只能是整型和字符型。
2)法则一:任何数左移(右移)32的倍数位等于该数本身。
3)法则二:在位移运算m<<n的计算中,若n为正数,则实际移动的位数为n%32,若n为负数,则实际移动的位数为(32+n%32),右移同理。
4)左移是乘以2的幂,对应着右移则是除以2的幂。
5)位运算要用补码来运算,拿到结果后再转原码
3、位运算的常用场景
1)m*2^n m乘以2的n次方
结果就是:m << n
原理:二进制,满二进一嘛
2)判断一个数的奇偶性
n&1 == 1 ? "奇数" : "偶数"
原理:1的二进制数为0000...00000001,偶数的最低位一定是0,奇数的最低位一定是1
任何数跟1做&运算,除了最低位,其他位的结果都是0,而奇数最低位是1,根据&运算规则,结果就是1
而偶数最低位是0,结果就是0。
3)通过^异或运算,交换两个数的值
int a = 3, b = 4;
a = a ^ b;
b = b ^ a;//由于a = a ^ b,所以 b ^ a = b ^ (a ^ b) = b ^ b ^ a = 0 ^ a = a;这样a的值就赋给b了
a = a ^ b;//由于a = a ^ b,b已经=a了,所以 a ^ b = (a ^ b) ^ a = a ^ a ^ b = b;这样b的值就赋给a了
这就完成了两个数的交换
原理:可以根据^运算原理一步步手写验证。
规则:
① a ^ a = 0
② a ^ b = b ^ a
③ a ^b ^ c = a ^ (b ^ c) = (a ^ b) ^ c;
④ d = a ^b ^ c 可以推出 a = d ^ b ^ c.
⑤ a ^ b ^a = b.
4)取绝对值 (a ^ (a >> 31)) - (a >> 31)
原理:任何正数右移31后只剩符号位0,最终结果为0,
任何负数右移31后也只剩符号位1,溢出的31位截断,空出的31位补符号位1,最终结果为-1.(负数要先求补码,算完后再转原码)。所以,右移31操作可以取得任何整数的符号位。
a >> 31 取得a的符号,若a为正数,a >> 31 等于0,a ^ 0 = a,不变;
若a为负数,a >> 31 等于-1 ,a ^ -1 翻转每一位;
最后 - (a >> 31),(因为 a >> 31 为0或-1,所以减 a >> 31 要么加0要么加1)
正数时,符号位为0,也就是 a >> 31 == 0,整个计算等效于 a ^ 0 + 0 = a;
负数时,符号位为-1,也就是 a >> 31 == -1,整个计算等效于 a ^ -1 - (-1) = a ^ -1 + 1 = ~a + 1
负数求绝对值的位运算 负数a的绝对值为~a + 1解读:
假设 a = -5;
二进制为:10000101
补码为: 11111010 + 1 = 11111011
取反为: 00000100
取反后加1:00000100 + 1 = 00000101
十进制为:+5