初识java《位运算》

634 阅读4分钟

最近在对接物联网的时候,传输的都是使用二进制,各种高低位和类型的转变和判断,(这个时候就想起了json的好处了)这段时间获益匪浅。刚好简单地聊一下这些天的收获。

一.原码、反码和补码

以前在学习计算机知识的时候,大概的知道机器是使用二进制来进行运算的,现在明白了对于二进制来说有三个概念:原码、反码和补码。以java中的byte为例,一个byte8位—>0000 0000 对于有符号的来说,第一个0表示符号,0表示正数,1表示负数。如果byte a = 3在二进制表示就是:0000 0011;如果byte b=-3在二进制里表示就是1000 0011。这个时候就知道了java中的byte类型的范围是-128到127之间。二进制的原码就是原来的码,其实就是一个数在二进制的表示,而对于反码来说,正数的反码等于自己的原码,而负数的反码就是它原码的符号位不变,其他的位置的位数取反。比如byte b= -3,他的反码就是1111 1100;对于补码来说,正数的补码等同于原码,而负数的补码等于他的反码+1。就拿刚才的-3来说,他的补码就是1111 1101;总结之后就是:**1.**正数的原码、反码和补码都是一样;**2.**负数的反码=他的原码符号位不变,其他位数取反(0->1,1->0);**3.**负数的补码等于他的反码+1;以前我也有疑问,为什么二进制需要分这三种概念。后来明白了二进制在进行运算的时候都是使用补码来进行的。比如1-1,在二进制中是1+(-1),前面说到对于有符号的来说,二进制的第一位表示正负,如果直接把原码进行运算那肯定会冲突。所以后来就转换成补码来进行运算。

二.位运算的符号及实践

三种有符号的位运算:按位与&(参与运算的进制的补码如果同为1,结果就是1不然就是0)、按位或|(参与运算的进制的补码如果有一个为1,结果就是1,不然就是0)、按位异或^(参与运算的进制的补码如果有一个为1、另一个为0,结果就是1,不然结果为0)。比如:1.按位与:如果是2&3的话,2的补码等于原码->0000 0010、3的补码等于原码->0000 0011;运算后的结果就是0000 0010转换为10进制表示就是2,所以2&3=2;如果2&-3的话,那就是0000 0010 & 1111 1101->0000 0000结果就是0;2.按位或:如果2|3->0000 0010 | 0000 0011 = 0000 0011->3,所以2|3=3;如果是2|-3的话->0000 0010 | 1111 1101 = 1111 1111->127刚好就是java中byte字节的最大值;3.按位异或:2^3->0000 0010 ^ 0000 0011 = 0000 0001->1如果是2^-3->0000 0010 ^ 1111 1101 = 1111 1111 = 127。

三.HsahMap中的取模运算

如果在java中寻找位运算的话,可能目前我最先想到的就是HsahMap。之前我们知道HsahMap使用的数据结构是数组+链表,在jdk1.8之前,HsahMap的数据的存储过程,会先计算key的hash值,然后通过对数组长度取模的方式,来计算当前数据在数组上的位置,最后把value值放在链表上。在jdk1.8之后,HsahMap会通过位运算来计算当前数据的在数组上的位置,上文了解到机器会用二进制的补码来计算,如果直接通过位运算的与运算会节省成倍的运算时间。其实我们在自定义HsahMap容量的时候,不管我们new一个HsahMap的长度为9或者10的时候,他的内部都会自动转换为2的次方数。除了这个地方之外HsahMap还有很多地方的计算都替换成了位运算。