在學習任何語言時,都會提及到一種容易被大家忽視的運算方法–>位運算
在java中,由於JVM機制的存在,使得位運算存在感更加低,並且,爲了程序的可讀性,也有程序員不願意使用位運算進行操作。
但是位運算的優秀性能,作爲一個程序員是不得不學習,不管是否會用到,都應學習學習其中的原理及思想,這給我們帶來的影響是潛移默化的。
基本位運算符 : & | ^ ~ << >> >>
這裏咱們就來說說其中的異或 ^
異或,顧名思義就是相異爲真
例如:
public class Demo8 {
public static void main(String[] args){
int x=0b11001; // 25
int y=0b10101; // 21
System.out.println(x^y);
// print 12
// 11001^10101=01100
}
}
相同位上存在1和0即爲1,其他均爲0,也就是異或中出現的1必定是兩個二進制數中有一個的對應爲上必定爲1且另一個數對應位必定爲0,即對應位上必定不同,這也就引出了在異或中非常經典的用法,即交換數值
首先,在咱們傳統的想法上,交換兩數數值如下:
public class Demo8 {
public static void main(String[] args){
int x=1;
int y=2;
int z;
z=x;
x=y;
y=z;
// y=1,x=2
}
}
也就是利用第三個中間變量達到簡單直接的交換效果,也是泛用廣的一種方法。
聰明一點的同學也可能會發現不需要中間變量也可以實現兩數數值交換效果,
如下:
public class Demo8 {
public static void main(String[] args){
int x=1;
int y=2;
x=x+y;
y=x-y;
x=x-y;
// y=1,x=2
}
}
而異或操作,類似與上面的算法,但是原理也正如我上面講的,提出兩數不同的部分,先看例子:
public static void main(String[] args){
int x=11; // 1011
int y=7; // 0111
x=x^y;
// x=1011^0111=1100 1100就是兩個二進制數的不同部分
y=x^y;
// y=1100^0111=1011
x=x^y;
// x=1100^1011=0111
System.out.println(x+" "+y);
// print 7 11
}
相信大家之前一定也瞭解過這種算法,但是其原理或許略知一二
原理很簡單,首先,我們將11和7的二進制數1011和0111進行異或,取出他們的不同部分,即1100(下面就稱其爲不同部分)。拿到不同部分了,然後怎麼辦呢?
不同部分爲1100,就是11爲不同的位,00位相同的位,也就是說00位上是兩個數都爲1或0的位,而11位是兩個數只有一個爲1的部分,那麼,如果我那1100和其中一個數再做異或會怎樣呢?爲什麼會交換數呢?
首先,那到不同部分1100,既然知道11位上必定有一個數爲1,有一個數爲0,那麼,拿去異或,爲1的和1異或就爲0,就成了另一個數上對應位的值(因爲這個數爲1,另一個數必定是0),如果1是和0異或,那麼相對的就爲1了,同樣的道理。而至於0值,拿去異或,被異或的數相對位上原本是什麼數就該是什麼數,不會變(而且這個0位上的值是兩個數相同的值)
同樣拿上面的11和7舉例,x=1011和y=0111,不同部分爲1100,拿去和x異或,因爲不同點前兩位爲0,所以x的第一位和第二位保持原樣不變,該是0就是0,該是1就是1,而且y上第一位和第二位必定和x的前兩位相同,因爲只有相同異或出來的結果才爲0。而第三位不同部分爲1,和x異或後,因爲x第三位爲0,所以不同,x第三位變爲1,但是想想,既然不同部分第三位爲1,那麼x的第三位和y的第三位必定不同,既然x爲0,那麼y的第三位必定爲1,所以x的第三位順理成章的就變成的y的第三位,第四位同理,不同部分爲1,而x第四位爲1,所以異或後必定爲0,而既然不同部分爲1,那麼x第四位和y第四位必定不同,既然x第四位爲1,那麼y的第四位必定爲0,所以異或後x第四位就變成了和y的第四位相同,又因爲不同部分的00位必定是x和y相同的,而異或後x和y的不同位又因爲異或變成了和y相同的值,也就是說,此時x和不同部分異或後,二進制上變成了y的值了,如果在用y和不同部分異或,同樣的道理,就變成了x的值了。
至於爲什麼沒用到第三個數,道理和之前的第二個例子一樣,臨時用x做了一個存放不同部分的容器,然後y=x^y,因爲此時x爲不同部分,和y異或後,如上所述,就變成了x的二進制了,如果再讓x(不同部分)與此時的y(此時已經變成x的值了)異或,即x=x^y,因爲y此時已經爲x的值了,所以不同部分和x異或後,自然會得到y的二進制,即y的值,也就是說此時x爲y的值。
綜上所述,就完成了我上面那個例子的整個過程。
如果有些朋友還不能理解,可以拿筆在紙上簡單畫一畫,很快就能理解了。
位運算的優勢無非是在於直接在機器層面對數進行操作了,因爲計算機的數據存儲均爲二進制,所以理論上是能操作所有數值的,當然,具體還得根據情況而定,不然也會得到出人意料的結果。
至於位運算的取捨,有人不願意爲了提升這百分之幾的性能而混淆代碼的可讀性,有人又認爲性能纔是程序之根本,尤其是在進行嵌入式等底層開發上,所以這就是仁者見仁智者見智了。