Integer.highestOneBit(int i)方法的做用與底層實現

在Integer類中有這麼一個方法,你能夠給它傳入一個數字,它將返回小於等於這個數字的一個2的冪次方數。這個方法就是highestOneBit(int i)。java

好比下面的Demo,注意方法的輸入與返回值:微信

System.out.println(Integer.highestOneBit(15));  // 輸出8
System.out.println(Integer.highestOneBit(16));  // 輸出16
System.out.println(Integer.highestOneBit(17));  // 輸出16
複製代碼

這個方法的實現代碼量也是很是少的:分佈式

public static int highestOneBit(int i) {
	// HD, Figure 3-1
	i |= (i >>  1);
	i |= (i >>  2);
	i |= (i >>  4);
	i |= (i >>  8);
	i |= (i >> 16);
	return i - (i >>> 1);
}
複製代碼

接下來,咱們就來詳細分析一下這塊代碼的邏輯。微服務

首先,對於這個方法的功能:給定一個數字,找到小於或等於這個數字的一個2的冪次方數。學習

若是咱們要本身來實現的話,咱們須要知道:怎麼判斷一個數字是2的冪次方數。spa

說真的,我一下想不到什麼好方法來判斷,惟一能想到的就是一個數字若是把它轉換成二進制表示的話,它會有一個規律:若是一個數字是2的冪次方數,那麼它對應的二進制表示僅有一個bit位上是1,其餘bit位全爲0。 好比: 十進制6,二進制表示爲:0000 0110 十進制8,二進制表示爲:0000 1000 十進制9,二進制表示爲:0000 1001 因此,咱們能夠利用一個數字的二進制表示來判斷這個數字是否是2的冪次方數。關鍵代碼怎麼實現呢?去遍歷每一個bit位?能夠,可是很差,那怎麼辦?咱們仍是回頭仔細看看Integer是如何實現的吧?code

public static int highestOneBit(int i) {
	// HD, Figure 3-1
	i |= (i >>  1);
	i |= (i >>  2);
	i |= (i >>  4);
	i |= (i >>  8);
	i |= (i >> 16);
	return i - (i >>> 1);
}
複製代碼

咱們發現這段代碼中沒有任何的遍歷,只有位運算與一個減法,也就是說它的實現思路和咱們本身的實現思路徹底不同,它的思路就是:給定一個數字,經過一系列的運算,獲得一個小於或等於該數字的一個2的冪次方數。cdn

也就是:若是給定一個數字18,經過運算後,要獲得16。it

18用二進制表示爲: 0001 0010io

想要獲得的結果(16)是:0001 0000

那麼這個運算的過程無非就是將18對應的二進制數中除最高位的1以外的其餘bit位都清零,則拿到了咱們想要的結果。

那怎麼經過位運算來實現這個過程呢?

咱們拿18對應的二進制數0001 0010來舉個例子就好了: 先將0001 0010右移1位, 獲得0000 1001,再與自身進行或運算: 獲得0001 1011

再將0001 1011右移2位, 獲得0000 0110,再與自身進行或運算: 獲得0001 1111

再將0001 1111右移4位, 獲得0000 0001,再與自身進行或運算: 獲得0001 1111

再將0001 1111右移8位, 獲得0000 0000,再與自身進行或運算: 獲得0001 1111

再將0001 1111右移16位, 獲得0000 0000,再與自身進行或運算: 獲得0001 1111

再將0001 1111無符號右移1位, 獲得0000 1111

關於無符號右移,能夠看我以前寫的文章。

最後用0001 1111 - 0000 1111 = 0001 0000 震驚!獲得了咱們想要的結果。

其實這個過程能夠抽象成這樣: 如今有一個二進制數據,0001****,咱們不關心低位的取值狀況,咱們對其進行右移而且進行或運算。

先將0001****右移1位, 獲得00001***,再與自身進行或運算: 獲得00011***

再將00011***右移2位, 獲得0000011*,再與自身進行或運算: 獲得0001111*

再將0001111*右移4位, 獲得00000001,再與自身進行或運算: 獲得00011111

後面不用再推算了,到這裏咱們其實能夠發現一個規律: 右移與或運算的目的就是想讓某個數字的低位都變爲1,再用該結果 減去 該結果右移一位後的結果,則至關於清零了原數字的低位。即獲得了咱們想要的結果。

到此,只能感嘆JDK做者對於位運算的使用已經達到了出神入化的境界了。

若是想學習更多的精彩的Java、分佈式、微服務等方面的知識,請關注微信公衆號:1點25

reny125.jpeg
相關文章
相關標籤/搜索