摘自 JavaGuide (「Java學習+面試指南」一份涵蓋大部分 Java 程序員所需要掌握的核心知識。準備 Java 面試,首選 JavaGuide!)
自增自減運算符
在寫代碼的過程中,常見的一種情況是需要某個整數類型變量增加 1 或減少 1,Java 提供了一種特殊的運算符,用於這種表達式,叫做自增運算符(++)和自減運算符(--)。
++ 和 -- 運算符可以放在變量之前,也可以放在變量之後,當運算符放在變量之前時(前綴),先自增/減,再賦值;當運算符放在變量之後時(後綴),先賦值,再自增/減。例如,當 b = ++a
時,先自增(自己增加 1),再賦值(賦值給 b);當 b = a++
時,先賦值(賦值給 b),再自增(自己增加 1)。也就是,++a 輸出的是 a+1 的值,a++輸出的是 a 值。用一句口訣就是:“符號在前就先加/減,符號在後就後加/減”。
移位運算符
移位運算符是最基本的運算符之一,幾乎每種編程語言都包含這一運算符。移位操作中,被操作的數據被視爲二進制數,移位就是將其向左或向右移動若干位的運算。
移位運算符在各種框架以及 JDK 自身的源碼中使用還是挺廣泛的,HashMap
(JDK1.8) 中的 hash
方法的源碼就用到了移位運算符:
static final int hash(Object key) {
int h;
// key.hashCode():返回散列值也就是hashcode
// ^ :按位異或
// >>>:無符號右移,忽略符號位,空位都以0補齊
return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}
在 Java 代碼裏使用 <<
、 >>
和>>>
轉換成的指令碼運行起來會更高效些。
掌握最基本的移位運算符知識還是很有必要的,這不光可以幫助我們在代碼中使用,還可以幫助我們理解源碼中涉及到移位運算符的代碼。
Java 中有三種移位運算符:
<<
:左移運算符,向左移若干位,高位丟棄,低位補零。x << 1
,相當於 x 乘以 2(不溢出的情況下)。>>
:帶符號右移,向右移若干位,高位補符號位,低位丟棄。正數高位補 0,負數高位補 1。x >> 1
,相當於 x 除以 2。>>>
:無符號右移,忽略符號位,空位都以 0 補齊。
由於 double
,float
在二進制中的表現比較特殊,因此不能來進行移位操作。
移位操作符實際上支持的類型只有int
和long
,編譯器在對short
、byte
、char
類型進行移位前,都會將其轉換爲int
類型再操作。
如果移位的位數超過數值所佔有的位數會怎樣?
當 int 類型左移/右移位數大於等於 32 位操作時,會先求餘(%)後再進行左移/右移操作。也就是說左移/右移 32 位相當於不進行移位操作(32%32=0),左移/右移 42 位相當於左移/右移 10 位(42%32=10)。當 long 類型進行左移/右移操作時,由於 long 對應的二進制是 64 位,因此求餘操作的基數也變成了 64。
也就是說:x<<42
等同於x<<10
,x>>42
等同於x>>10
,x >>>42
等同於x >>> 10
。
左移運算符代碼示例 :
int i = -1;
System.out.println("初始數據: " + i);
System.out.println("初始數據對應的二進制字符串: " + Integer.toBinaryString(i));
i <<= 10;
System.out.println("左移 10 位後的數據 " + i);
System.out.println("左移 10 位後的數據對應的二進制字符 " + Integer.toBinaryString(i));
輸出:
初始數據: -1
初始數據對應的二進制字符串: 11111111111111111111111111111111
左移 10 位後的數據 -1024
左移 10 位後的數據對應的二進制字符 11111111111111111111110000000000
由於左移位數大於等於 32 位操作時,會先求餘(%)後再進行左移操作,所以下面的代碼左移 42 位相當於左移 10 位(42%32=10),輸出結果和前面的代碼一樣。
int i = -1;
System.out.println("初始數據: " + i);
System.out.println("初始數據對應的二進制字符串: " + Integer.toBinaryString(i));
i <<= 42;
System.out.println("左移 10 位後的數據 " + i);
System.out.println("左移 10 位後的數據對應的二進制字符 " + Integer.toBinaryString(i));
右移運算符使用類似,篇幅問題,這裏就不做演示了。