詳解Java的位運算
位運算
很久以前學習過位運算,但是很久不用,感覺都忘得差不多了。最近看了幾處位運算的代碼,發(fā)現(xiàn)都看不懂了,哈。也是時候回來補一補基礎(chǔ)知識了。
程序中的所有數(shù)在計算機內(nèi)存中都是以二進制的形式儲存的。位運算就是直接對整數(shù)在內(nèi)存中的二進制位進行操作。
位運算的運算符:
運算符 | 含義 |
& | 按位與 |
| | 按位或 |
~ | 按位取反 |
^ | 按位異或 |
<< | 左移 |
>> | 帶符號右移 |
>>> | 無符號右移 |
這些算是很基礎(chǔ)的知識了,但是太久不用,還是難免會遺忘了,在編碼的同時,可以多多使用!
Talk is cheap, show me the code.
說明:單獨討論這些確實是很難看到應(yīng)用的地方,如果有不太清楚的可以去看看其他人的總結(jié)。
我們以一個代碼來看看位運算的應(yīng)用:
public final void writeInt(int v) throws IOException { out.write((v >>> 24) & 0xFF); out.write((v >>> 16) & 0xFF); out.write((v >>> 8) & 0xFF); out.write((v >>> 0) & 0xFF); incCount(4); }
這段代碼是 DataOutputStream
類中的一個方法,用于將一個 int 型的整數(shù)寫入流中。這個方法的命名是很有意思的,它和 OutputStream
中的 public abstract void write(int b) throws IOException
這個方法是完全不同的。這個方法的參數(shù)似乎是表示它可以將一個 int 型整數(shù)寫入流中,但是方法的功能不是靠猜測的,而是要看方法的描述。
public abstract void write(int b) throws IOException
API 中的介紹:
Writes the specified byte to this output stream. The general contract for write is that one byte is written to the output stream. The byte to be written is the eight low-order bits of the argument b. The 24 high-order bits of b are ignored.
它是將一個特定的字節(jié)寫入流中,我們知道一個int型變量占32位,一個byte占8位,所以一個小于256(2^8)的int型整數(shù)和byte型整數(shù)的最后8位是相同的。
因此這個方法是寫入一個int型變量的最低8位,而將剩下的24位忽略。使用這個方法的時候,要格外注意!
The byte to be written is the eight low-order bits of the argument b. The 24 high-order bits of b are ignored.
所以,將一個int型的變量完整的寫入流中,并不是一個很簡單的問題。讓我們再回到上面這端代碼: 它是連續(xù)四次寫入,每次寫入一個字節(jié)的數(shù)據(jù),這樣一個int型的變量,就被變?yōu)?個字節(jié)寫入流中了。
out.write((v >>> 24) & 0xFF); 這個方法就是上面的寫入較低的8位數(shù)字,這個具體實現(xiàn)是相應(yīng)的子類提供的。
我們來看看圖解: 一個簡單的與運算:可以看出運算的結(jié)果是保留了低8位,這個就是 (v>>>24) & 0xFF 運算的結(jié)果。
那么如何獲取高8位的值呢?這就要使用移位運算進行操作了:
通過進行移位操作,就可以獲取每8位的數(shù)據(jù),然后再進行按位與 & 運算,就可以將一個int型整數(shù)完全的寫入流中了。
代碼演示
代碼
package dragon; /** * 分析這一個方法,目前水平有限,先從最簡單的做起! * */ // public final void writeInt(int v) throws IOException { // out.write((v >>> 24) & 0xFF); // out.write((v >>> 16) & 0xFF); // out.write((v >>> 8) & 0xFF); // out.write((v >>> 0) & 0xFF); // incCount(4); // } //上面這段代碼是將一個32位整型,寫入輸出流。 //并且是將32位整型分為4個部分,每次寫入8位。 //這是Java的特性。 public class DataOutputStreamAnalysis { public static void main(String[] args) { DataOutputStreamAnalysis analysis = new DataOutputStreamAnalysis(); analysis.analysis(65535); } public void analysis(int number) { int number1, number2, number3, number4; //后面的數(shù)字表示是一個32位整型的第幾個8位。 number1 = (number >>> 24) & 0xFF; number2 = (number >>> 16) & 0xFF; number3 = (number >>> 8) & 0xFF; number4 = (number >>> 0) & 0xFF; System.out.println(this.format(Integer.toBinaryString(number))+" 原始數(shù)據(jù)"); System.out.println(this.format(Integer.toBinaryString(number1))+" 原始數(shù)據(jù)第一個8位"); System.out.println(this.format(Integer.toBinaryString(number2))+" 原始數(shù)據(jù)第二個8位"); System.out.println(this.format(Integer.toBinaryString(number3))+" 原始數(shù)據(jù)第三個8位"); System.out.println(this.format(Integer.toBinaryString(number4))+" 原始數(shù)據(jù)第四個8位"); } /** * 輸入一個二進制字符串,將其格式化,因為整型是 * 占32位的,但是轉(zhuǎn)換成的二進制字符串,并沒有32位*/ public String format(String bstr) { int len = bstr.length(); StringBuilder sb = new StringBuilder(35); for (int i = 0; i < 32-len; i++) { sb.append("0"); } sb.append(bstr); sb.insert(8, " "); sb.insert(17, " "); sb.insert(26, " "); //前面插入一個字符后,所有字符的索引都變了! return sb.toString(); } }
結(jié)果
說明: 這里沒有考慮負數(shù)的情況,不過都是一樣的,只是負數(shù)的表示相對麻煩一點而已。只要理解正數(shù),負數(shù)也不是什么問題了。
位運算的應(yīng)用
1.判斷 int 型變量x是奇書還是偶數(shù)
將變量 x 和 1 進行按位與運算,如果結(jié)果為 0,則變量x為偶數(shù),否則為奇數(shù)。
if (x & 1 ==0) System.out.println("x是偶數(shù)"); if (x & 1 == 1) System.out.println("x是奇數(shù)");
說明:這個還是很好理解的,因為偶數(shù)的最后移位一定是 0。(二進制表示)
2.取 int 型變量 x 的第 k 位 將變量 x 右移 k 位,再和1進行邏輯與運算,結(jié)果即為變量 x 第 k 位的二進制值。
表達式:x >> k & 1 (推薦加上括號,這樣顯得更加清晰明了。)
3.將 int 型變量 x 的第 k 位置 1 將 1 左移 k 位,再和變量 x 進行邏輯或運算,則將變量 x 的第 k 位置 1,其它位保持不變。
表達式:x = x | (1 << k)
4.將 int 型變量的第 k 位 清 0 將 1 左移 k 位再取反,將其結(jié)果再和變量 下進行邏輯運算,則將變量 x 的第 k 位清 0,其它位保持不變。
表達式位:x = x & ~(1 << k)
5.計算兩個整數(shù)的平均值
表達式位:(x & y) + ((x ^ y) >> 1)
6.對于大于1 的整數(shù) x,判斷 x 是不是 2 的冪
if (x & (x-1) == 0) System.out.println("x是2的次冪");
7.將一個數(shù)乘以 2 的 n 次冪
表達式:x = x << n
例如:將 x 擴大 2 倍:x = x << 1
推薦使用位運算的原因:
位運算的速度是快于算術(shù)運算的,因為位運算需要的指令少,執(zhí)行所需要的時間就少,會顯得很快,但是只有在大量執(zhí)行的情況下才能看出來位運算的優(yōu)點。畢竟現(xiàn)在的計算機已經(jīng)越來越快了。
到此這篇關(guān)于詳解Java的位運算的文章就介紹到這了,更多相關(guān)Java位運算內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Spring Boot基礎(chǔ)學習之Mybatis操作中使用Redis做緩存詳解
這篇文章主要給大家介紹了關(guān)于Spring Boot基礎(chǔ)學習之Mybatis操作中使用Redis做緩存的相關(guān)資料,文中通過示例代碼介紹的非常詳細,對大家學習或者使用spring boot具有一定的參考學習價值,需要的朋友們下面來一起看看吧2018-11-11idea springboot 修改css,jsp不重啟實現(xiàn)頁面更新的問題
這篇文章主要介紹了idea springboot 修改css,jsp不重啟實現(xiàn)頁面更新的問題,本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下2020-10-10計算Java數(shù)組長度函數(shù)的方法以及代碼分析
在本篇內(nèi)容里,小編給大家整理了關(guān)于計算Java數(shù)組長度函數(shù)的方法以及代碼分析內(nèi)容,有興趣的朋友么可以學習參考下。2022-11-11Spring、SpringMVC和SpringBoot的區(qū)別及說明
這篇文章主要介紹了Spring、SpringMVC和SpringBoot的區(qū)別及說明,具有很好的參考價值,希望對大家有所幫助。2022-10-10