java 位运算符在实际开发中的用处_java 位运算 和实际应用
public?class?Test?{
public?static?void?main(String[]?args)?{
//?1、左移(?<
//?0000?0000?0000?0000?0000?0000?0000?0101?然后左移2位后,低位補0://
//?0000?0000?0000?0000?0000?0000?0001?0100?換算成10進制為20
System.out.println(5?<
//?2、右移(?>>?)?高位補符號位
//?0000?0000?0000?0000?0000?0000?0000?0101?然后右移2位,高位補0:
//?0000?0000?0000?0000?0000?0000?0000?0001
System.out.println(5?>>?2);//?運行結(jié)果是1
//?3、無符號右移(?>>>?)?高位補0
//?例如?-5換算成二進制后為:0101?取反加1為1011
//?1111?1111?1111?1111?1111?1111?1111?1011
//?我們分別對5進行右移3位、?-5進行右移3位和無符號右移3位:
System.out.println(5?>>?3);//?結(jié)果是0
System.out.println(-5?>>?3);//?結(jié)果是-1
System.out.println(-5?>>>?3);//?結(jié)果是536870911
//?4、位與(?&?)
//?位與:第一個操作數(shù)的的第n位于第二個操作數(shù)的第n位如果都是1,那么結(jié)果的第n為也為1,否則為0
System.out.println(5?&?3);//?結(jié)果為1
System.out.println(4?&?1);//?結(jié)果為0
//?5、位或(?|?)
//?第一個操作數(shù)的的第n位于第二個操作數(shù)的第n位?只要有一個是1,那么結(jié)果的第n為也為1,否則為0
System.out.println(5?|?3);//?結(jié)果為7
//?6、位異或(?^?)
//?第一個操作數(shù)的的第n位于第二個操作數(shù)的第n位?相反,那么結(jié)果的第n為也為1,否則為0
System.out.println(5?^?3);//結(jié)果為6
//?7、位非(?~?)
//?操作數(shù)的第n位為1,那么結(jié)果的第n位為0,反之。
System.out.println(~5);//?結(jié)果為-6
}
}
難點解析:
1 :正數(shù) 和負數(shù) 二進制如何轉(zhuǎn)化?
5 的二進制數(shù) 轉(zhuǎn)化為-5的二進制數(shù) ,換算方法: 取反+1.
同樣 ?-5 的二進制數(shù) 轉(zhuǎn)化為5的二進制數(shù) ,換算方法: 取反+1.
2 符號解析:
>>>是無符號右移,在高位補零
>>是帶符號的右移,如果是正數(shù)則在高位補零,負數(shù)則補1
int a = -1;
System.out.println(a>>1);
System.out.println(a>>>1);
結(jié)果:
-1
2147483647
1111 1111 1111 1111 1111 1111 1111 1111 ? ? ? -1
1111 1111 1111 1111 1111 1111 1111 1111 ? ? ? -1
0111 1111 1111 1111 1111 1111 1111 1111 ? ? ? 2147483647
3 ?符號的實際含義:
Java整型數(shù)據(jù)類型有:byte、char、short、int、long。要把它們轉(zhuǎn)換成二進制的原碼形式,必須明白他們各占幾個字節(jié)。我們都知道,一個字節(jié)占8位。
數(shù)據(jù)類型?????????????????????????? 所占位數(shù)
byte?????????????????????????????????????? 8
boolean????????????????????????????????8
short??????????????????????????????????? 16
int???????????????????????????????????????? 32
long????????????????????????????????????? 64
float??????????????????????????????????????32
double????????????????????????????????? 64
char???????????????????????????????????? 16
還需要明白一點的是:計算機表示數(shù)字正負不是用+ -加減號來表示,而是用最高位數(shù)字來表示,0表示正,1表示負
由于數(shù)據(jù)類型所占字節(jié)是有限的,而位移的大小卻可以任意大小,所以可能存在位移后超過了該數(shù)據(jù)類型的表示范圍,于是有了這樣的規(guī)定:
如果為int數(shù)據(jù)類型,且位移位數(shù)大于32位,則首先把位移位數(shù)對32取模,不然位移超過總位數(shù)沒意義的。所以4>>32與4>>0是等價的。
如果為long類型,且位移位數(shù)大于64位,則首先把位移位數(shù)對64取模,若沒超過64位則不用對位數(shù)取模。
如果為byte、char、short,則會首先將他們擴充到32位,然后的規(guī)則就按照int類型來處理。
<
>>表示右移, 右移一位表示原來的值除2.
位運算符包括: 與(&)、非(~)、或(|)、異或(^)&:當兩邊操作數(shù)的位同時為1時,結(jié)果為1,否則為0。如1100&1010=1000 | :當兩邊操作數(shù)的位有一邊為1時,結(jié)果為1,否則為0。如1100|1010=1110 ~:0變1,1變0 ^:兩邊的位不同時,結(jié)果為1,否則為0.如1100^1010=0110
位運算與位移動運行符的一個場景:HashMap的功能是通過“鍵(key)”能夠快速的找到“值”。下面我們分析下HashMap存數(shù)據(jù)的基本流程:?1、當調(diào)用put(key,value)時,首先獲取key的hashcode,int
hash = key.hashCode();?2、再把hash通過一下運算得到一個int
h.?hash ^= (hash >>> 20) ^ (hash >>> 12);?int h = hash ^ (hash >>> 7) ^ (hash >>> 4);?為什么要經(jīng)過這樣的運算呢?這就是HashMap的高明之處。先看個例子,一個十進制數(shù)32768(二進制1000
0000 0000 0000),經(jīng)過上述公式運算之后的結(jié)果是35080(二進制1000 1001 0000
1000)。看出來了嗎?或許這樣還看不出什么,再舉個數(shù)字61440(二進制1111 0000 0000
0000),運算結(jié)果是65263(二進制1111 1110 1110
1111),現(xiàn)在應該很明顯了,它的目的是讓“1”變的均勻一點,散列的本意就是要盡量均勻分布。3、得到h之后,把h與HashMap的承載量(HashMap的默認承載量length是16,可以自動變長。在構造HashMap的時候也可以指定一個長
度。這個承載量就是上圖所描述的數(shù)組的長度。)進行邏輯與運算,即 h &
(length-1),這樣得到的結(jié)果就是一個比length小的正數(shù),我們把這個值叫做index。其實這個index就是索引將要插入的值在數(shù)組中的
位置。第2步那個算法的意義就是希望能夠得出均勻的index,這是HashTable的改進,HashTable中的算法只是把key的
hashcode與length相除取余,即hash %
length,這樣有可能會造成index分布不均勻。還有一點需要說明,HashMap的鍵可以為null,它的值是放在數(shù)組的第一個位置。4、我們用table[index]表示已經(jīng)找到的元素需要存儲的位置。先判斷該位置上有沒有元素(這個元素是HashMap內(nèi)部定義的一個類Entity,
基本結(jié)構它包含三個類,key,value和指向下一個Entity的next),沒有的話就創(chuàng)建一個Entity對象,在
table[index]位置上插入,這樣插入結(jié)束;如果有的話,通過鏈表的遍歷方式去逐個遍歷,看看有沒有已經(jīng)存在的key,有的話用新的value替
換老的value;如果沒有,則在table[index]插入該Entity,把原來在table[index]位置上的Entity賦值給新的
Entity的next,這樣插入結(jié)束。下面講解一下原碼->反碼->補碼之間的相互關系[-3]反=[10000011]反=11111100?原碼 ? ? ? ? ? ?反碼負數(shù)的補碼是將其原碼除符號位之外的各位求反之后在末位再加1。?[-3]補=[10000011]補=11111101?原碼 ? ? ? ? ?補碼也就是說原碼轉(zhuǎn)換成補碼是先原碼 ?反碼 最后+1成補碼。位運算都是補碼運算的,所以位運算后要再取反+1才得到真正的原碼。應用舉例?(1) 判斷int型變量a是奇數(shù)還是偶數(shù) ? ? ? ? ? ?a&1 ?= 0 偶數(shù)?a&1 = ?1 奇數(shù)?(2) 取int型變量a的第k位 (k=0,1,2……sizeof(int)),即a>>k&1?(3) 將int型變量a的第k位清0,即a=a&~(1 < >16-k ?(設sizeof(int)=16)?(6) int型變量a循環(huán)右移k次,即a=a>>k |a < <16-k ?(設sizeof(int)=16)?(7)整數(shù)的平均值?對于兩個整數(shù)x,y,如果用 (x+y)/2 求平均值,會產(chǎn)生溢出,因為 x+y 可能會大于INT_MAX,但是我們知道它們的平均值是肯定不會溢出的,我們用如下算法:?int average(int x, int y) ?//返回X,Y 的平均值?{ ? ?return (x&y)+((x^y)>>1);?}?(8)判斷一個整數(shù)是不是2的冪,對于一個數(shù) x >= 0,判斷他是不是2的冪?boolean power2(int x)?{?return ((x&(x-1))==0)&&(x!=0);?}?(9)不用temp交換兩個整數(shù)?void swap(int x , int y)?{?x ^= y;?y ^= x;?x ^= y;?}?(10)計算絕對值?int abs( int x )?{?int y ;?y = x >> 31 ;?return (x^y)-y ; ? ? ? ?//or: (x+y)^y?}?(11)取模運算轉(zhuǎn)化成位運算 (在不產(chǎn)生溢出的情況下)?a % (2^n) 等價于 a & (2^n - 1)?(12)乘法運算轉(zhuǎn)化成位運算 (在不產(chǎn)生溢出的情況下)?a * (2^n) 等價于 a < < n?(13)除法運算轉(zhuǎn)化成位運算 (在不產(chǎn)生溢出的情況下)?a / (2^n) 等價于 a>> n?例: 12/8 == 12>>3?(14) a % 2 等價于 a & 1 ? ? ? ?(15) if (x == a) x= b;?else x= a;?等價于 x= a ^ b ^ x;?(16) x 的 相反數(shù) 表示為 (~x+1)
針對以上代碼分析如下:
~1、 y = x > > 31 ;//右移31位,只保留符號位,如果是負數(shù),則是-1,其二進制為1111 1111 1111 1111,全為1,如果是正數(shù),則全0~2、x^y//X與Y的異或運算,按位進行異或,當y=0時,實際上二者異或后運算的值保持不變,當Y=-1時,則實際上是將原值每位求反(1變成0,0變成1)~3、-y//當y為0時保持不變,為-1時,則表示加1,因此(x^y)-y當Y=0時,表示保持x不變,當y=-1時,則表示將x各位求反后加1,實際上就是對該數(shù)求負,由于原來就是負數(shù),因此就是變成正數(shù)。綜上所述,該過程就是求絕對值。~6. ?取模運算,采用位運算實現(xiàn):a % (2^n) 等價于 a & (2^n - 1)?~7. ?乘法運算 ? 采用位運算實現(xiàn)a * (2^n) 等價于 a << n~8. ? 除法運算轉(zhuǎn)化成位運算a / (2^n) 等價于 a>> n?~9. ? 求相反數(shù)(~x+1)?~10 ?a % 2 等價于 a & 1
6. ?取模運算,采用位運算實現(xiàn):
a % (2^n) 等價于 a & (2^n - 1)
7. ?乘法運算 ? 采用位運算實現(xiàn)
a * (2^n) 等價于 a << n
8. ? 除法運算轉(zhuǎn)化成位運算
a / (2^n) 等價于 a>> n
9. ? 求相反數(shù)(符號位也相反了)
(~x+1)
10 ?a % 2 等價于 a & 1
實例功能 ? ? ? ? ? ? ? | ? ? ? ? ?示例 ? ? ? ? ? ?| ? ?位運算?----------------------+-----------------------------+--------------------?去掉最后一位 ? ? ? ? ? | (101101->10110) ? ? ? ? ? | x >> 1?在最后加一個0 ? ? ? ? | (101101->1011010) ? ? ? ? | x < < 1?在最后加一個1 ? ? ? ? | (101101->1011011) ? ? ? ? | x < < 1+1?把最后一位變成1 ? ? ? | (101100->101101) ? ? ? ? ? | x | 1?把最后一位變成0 ? ? ?| (101101->101100) ? ? ? ? ? | x | 1-1?最后一位取反 ? ? ? ? ? | (101101->101100) ? ? ? ? ? | x ^ 1?把右數(shù)第k位變成1 ? ? ? | (101001->101101,k=3) ? ? ? | x | (1 < < (k-1))?把右數(shù)第k位變成0 ? ? ? | (101101->101001,k=3) ? ? ? | x & ~ (1 < < (k-1))?右數(shù)第k位取反 ? ? ? ? | (101001->101101,k=3) ? ? ? | x ^ (1 < < (k-1))?取末三位 ? ? ? ? ? ? ? | (1101101->101) ? ? ? ? ? ? | x & 7?取末k位 ? ? ? ? ? ? ? | (1101101->1101,k=5) ? ? ? | x & ((1 < < k)-1)取右數(shù)第k位 ? ? ? ? | (1101101->1,k=4) ? ? ? ? ? | x >> (k-1) & 1把末k位變成1 ? ? ? ? ? | (101001->101111,k=4) ? ? ? | x | (1 < < k-1)?末k位取反 ? ? ? ? ? ? | (101001->100110,k=4) ? ? ? | x ^ (1 < < k-1)?把右邊連續(xù)的1變成0 ? ? | (100101111->100100000) ? ? | x & (x+1)?把右起第一個0變成1 ? ? | (100101111->100111111) ? ? | x | (x+1)?把右邊連續(xù)的0變成1 ? ? | (11011000->11011111) ? ? | x | (x-1)?取右邊連續(xù)的1 ? ? ? ? | (100101111->1111) ? ? ? ? | (x ^ (x+1)) >> 1?去掉右起第一個1的左邊 | (100101000->1000) ? ? ? ? | x & (x ^ (x-1))?判斷奇數(shù) ? ? ? | (x&1)==1?判斷偶數(shù) | (x&1)==0 ? ? ??例如求從x位(高)到y(tǒng)位(低)間共有多少個1public static int FindChessNum(int x, int y, ushort k)?{?int re = 0;?for (int i = y; i <= x; i++)?{?re += ((k >> (i - 1)) & 1);?}?return re;?}
來源:http://blog.csdn.net/xiaoliuliu2050/article/details/52994805
總結(jié)
以上是生活随笔為你收集整理的java 位运算符在实际开发中的用处_java 位运算 和实际应用的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 随机森林降维matlab代码,随机森林代
- 下一篇: 揭开netty神秘面纱_Netty 源码