Java中特殊運算符及其應(yīng)用詳解
一、前言
當涉及位操作和位級運算時,Java 提供了一組特殊的運算符,即左移(<<
)和右移(>>
)運算符。這些運算符與普通的算術(shù)和邏輯運算符不同,它們操作的是數(shù)字的二進制位。位操作是計算機底層編程中常用的技巧,能夠高效地執(zhí)行一些操作,如數(shù)值乘除以2的冪次方,處理標志位,以及在一些位級編碼場景下進行數(shù)據(jù)處理。
左移和右移運算符用于將二進制位向左或向右移動指定的位數(shù),從而實現(xiàn)對數(shù)值的快速操作。左移操作將數(shù)值的二進制表示向左移動,等效于乘以2的冪次方,而右移操作將數(shù)值的二進制表示向右移動,等效于除以2的冪次方。這些運算符在處理大數(shù)據(jù)集、位掩碼、網(wǎng)絡(luò)協(xié)議以及嵌入式系統(tǒng)等領(lǐng)域都具有廣泛的應(yīng)用。
然而,需要注意的是,位操作并不常見于一般的業(yè)務(wù)邏輯編程,而更多地出現(xiàn)在需要對二進制數(shù)據(jù)進行處理的底層系統(tǒng)級編程中。在使用位操作時,應(yīng)該清晰地理解位操作的語義,防止出現(xiàn)意外錯誤。同時,要考慮到可讀性和代碼維護性,不應(yīng)濫用位操作,而是在合適的場景下使用,以提高代碼的效率和性能。
二、Java的左移、右移運算符
<<
是左移;如:<<1
就是左移一位;<<2
就是左移兩位>>”
是右移;如:>>1
就是右移一位;>>2
就是右移兩位
記憶技巧: 尖括號的方向朝向哪就是哪移。
左移就是將目標轉(zhuǎn)換為二進制后,從右向左移動一位,右邊補零,左邊移除。
右移就是將目標轉(zhuǎn)換為二進制后,從左向右移動一位,左邊補零,右邊移除。。
三、Java中左移、右移使用場景
可以代替乘(左移)和除(右移),如下:
package zd.hjd.test.synchronizedtest; public class MyTestMain { public static void main(String[] args) { System.out.println(4*2); System.out.println(4<<1); System.out.println(4/2); System.out.println(4>>1); } }
輸出結(jié)果:
8
8
2
2
四、使用左移、右移優(yōu)點和弊端
4.1 優(yōu)點
使用左移(<<)和右移(>>)的好處在于它們可以在某些情況下提供更高效的數(shù)值操作,特別是涉及到2的冪次方的操作。以下是一些使用左移右移的好處:
- 速度優(yōu)勢: 左移和右移操作是位級操作,它們在底層直接對二進制數(shù)據(jù)進行移動,相比于使用乘除法運算符,位移操作可以更快地完成數(shù)值的變換。這在一些需要高效計算的場景下尤為重要。
- 數(shù)值操作: 左移和右移可以用于實現(xiàn)數(shù)值的倍增或減少。例如,將一個數(shù)值左移n位,等效于將其乘以2的n次方;將一個數(shù)值右移n位,等效于將其除以2的n次方。
- 位掩碼操作: 在位掩碼操作中,可以使用左移來設(shè)置位,使用右移來讀取位。這在一些標志位、開關(guān)狀態(tài)的處理中非常有用。
- 位級編碼: 在某些編碼和解碼場景下,需要將信息編碼到特定的位上,或者從特定位上解碼信息。左移和右移操作可以用于實現(xiàn)這種位級的數(shù)據(jù)處理。
- 嵌入式系統(tǒng): 在嵌入式系統(tǒng)中,資源有限,效率至關(guān)重要。位移操作可以提供更緊湊和高效的代碼,減少資源消耗。
4.2 弊端
- 可讀性下降: 左移和右移操作對于非熟悉位操作的開發(fā)者來說可能不太直觀,代碼的可讀性可能會下降,使得代碼難以理解和維護。
- 位移越界: 在使用右移操作時,如果對有符號的整數(shù)進行右移,可能會導致符號位擴展,從而改變數(shù)值的意義。例如,對于負數(shù)的右移可能會導致意外的結(jié)果。
- 移位溢出: 如果使用左移操作將某個位移到超出數(shù)據(jù)類型的范圍,就會發(fā)生移位溢出,導致結(jié)果不正確。
- 代碼依賴于底層實現(xiàn): 使用位操作可能會使代碼與底層硬件或編譯器的實現(xiàn)相關(guān),導致代碼的可移植性下降。
- 復雜邏輯錯誤: 如果沒有正確地處理邊界情況,可能會導致復雜的邏輯錯誤,尤其是在涉及位級運算的復雜算法中。
- 難以維護: 過度使用位操作可能使代碼變得難以理解和維護,特別是在邏輯復雜的情況下。
- 代碼不易調(diào)試: 位操作可能會導致一些難以調(diào)試的問題,因為它們涉及底層位級表示,而不是更常見的數(shù)值操作。
五、使用左移、右移注意事項
1.帶符號左移需要考慮移動后數(shù)字變?yōu)樨摂?shù)的情況,因為二進制的首位為符號位。
2.從上述中我們知道,左移就是將一個數(shù)字的二進制編碼向左邊移動,右邊補零,右移相反。如果一個int
類型的數(shù)字向左移32位結(jié)果是不是就是0呢?答案是錯誤的。當int類型數(shù)字進行左移,并且左移位數(shù)大于等于32位時,會先與32求余,然再進行移動。32%32 = 0,使用int
類型向左移32位相當于不移動,byte
和short
類型同理。long
類型是64位。
public class MoveLeft { public static void main(String[] args) { int a = 10; byte b = 50; short s = 60; System.out.println(a >> 1);// 5 System.out.println(a << 1);// 20 System.out.println(a << 32);// 10 System.out.println(a << 33);// 20 System.out.println(b << 32);// 50 System.out.println(b << 33);// 100 System.out.println(s << 32);// 60 System.out.println(s << 33);// 120 long longValue = 733183670L; System.out.println("longValue:" + (longValue));//打印longValue System.out.println("longValue左移1位:" + (longValue << 1));//左移1位 System.out.println("longValue左移8位:" + (longValue << 8));//左移8位 //當long類型左移位數(shù)大于等于64位操作時,會先求余后再進行移位操作 System.out.println("longValue左移64位:" + (longValue << 64));//求余為64%64=0,相當于左移0位(不移位) System.out.println("longValue左移72位:" + (longValue << 72));//求余為72%64=8,相當于左移8位 System.out.println("longValue左移128位:" + (longValue << 128));//求余為128%64=0,相當于左移0位(不移位) } }
3.double和float不能使用位移來操作,編譯不通過。
六、無符號右移>>>
無符號右移和右移原理一樣,只不過是右移后在左邊補零后舍棄掉符號位。如下所示:
public class MoveLeft { public static void main(String[] args) { int a = -10; System.out.println(a >>> 1);// 結(jié)果是 2147483643 } }
執(zhí)行的過程如下:
//向得出-10的二進制,需要得到10的二進制 0000 0000 0000 0000 0000 0000 0000 ??1010??// 10 二進制如下 1111 1111 1111 1111 1111 1111 1111 0101// 10 的反碼 1111 1111 1111 1111 1111 1111 1111 0110 //反碼+1 就為 -10 的二進制 0111 1111 1111 1111 1111 1111 1111 1011// 右移一位 //轉(zhuǎn)換為10進制 為 2147483643
記住Java中沒有無符號左移。因為左移操作符 <<
總是保持符號位,即使在移動過程中可能會導致符號位變?yōu)?。如果需要進行無符號左移操作,可以使用無符號右移操作 >>>
來實現(xiàn)。因為在大多數(shù)情況下,無符號左移和無符號右移的效果是一樣的,都是向左或向右移動指定位數(shù),只是填充的位不同。
七、Java中的其它特殊運算符
7.1 &
按位與運算 &
是雙目運算符。其功能是參與運算的兩數(shù)各對應(yīng)的二進制位相與
。只有對應(yīng)的兩個二進位均為1時,結(jié)果位才為1 ,否則為0。參與運算的數(shù)以補碼方式出現(xiàn)。
使用場景:
- 位操作: 位運算符在底層數(shù)據(jù)處理和優(yōu)化中很常見,例如對數(shù)據(jù)進行位掩碼、位清除、位設(shè)置等操作。
- 權(quán)限控制: 在權(quán)限控制中,可以使用位運算來對不同權(quán)限進行組合或判斷。
- 位集合: 將每個位視為一個標志,可以通過按位與運算來檢查是否設(shè)置了特定的標志位。
例如,如果有一個整數(shù) a 表示某個權(quán)限的掩碼,另一個整數(shù) b 表示用戶的權(quán)限,通過 a & b
運算可以判斷用戶是否具有某個權(quán)限。
7.2 |
按位或運算 |
是雙目運算符。其功能是參與運算的兩數(shù)各對應(yīng)的二進制位相或。只要兩數(shù)的二進制位中有一個是1,那么按位或的結(jié)果就是1;只有二進制兩位都為0時,結(jié)果為0。
使用場景:
- 位操作: 位運算符在底層數(shù)據(jù)處理和優(yōu)化中很常見,例如對數(shù)據(jù)進行位標記、位組合等操作。
- 權(quán)限控制: 在權(quán)限控制中,可以使用位運算來對不同權(quán)限進行組合或判斷。
- 位集合: 將每個位視為一個標志,可以通過按位或運算來設(shè)置特定的標志位。
例如,如果有一個整數(shù) a 表示某個權(quán)限的掩碼,另一個整數(shù) b 表示用戶的權(quán)限,通過 a | b
運算可以將用戶的權(quán)限添加到掩碼中。
7.3 ^
按位異或運算 ~
是雙目運算符。其功能是參與運算的兩數(shù)各對應(yīng)的二進制位相異或。兩個數(shù)字的二進制位相同則取0,不同值則取1。
異或運算符具有以下的性質(zhì):
(1)交換律: (2)結(jié)合律:
(a^b)^c == a^(b^c)
(3)對于任何數(shù)X,都有:
x^x=0,x^0=x
(4)自反性
A XOR B XOR B = A xor 0 = A
使用場景:
異或運算最常見于多項式除法,不過它最重要的性質(zhì)還是自反性:A XOR B XOR B = A
,即對給定的數(shù)A,用同樣的運算因子(B)作兩次異或運算后仍得到A本身。這是一個神奇的性質(zhì),利用這個性質(zhì),可以獲得許多有趣的應(yīng)用。
例如,大部分程序教科書都會向初學者指出,要交換兩個變量的值,必須要引入一個中間變量。但如果使用異或,就可以節(jié)約一個變量的存儲空間: 設(shè)有A,B兩個變量,存儲的值分別為a,b,則以下三行表達式將互換他們的值 表達式 (值) :
A=A XOR B (a XOR b)
B=B XOR A (b XOR a XOR b = a)
A=A XOR B (a XOR b XOR a = b)
public class MyTestMain { public static void main(String[] args) { int a = 5; int b = 6; a = a^b; b = a^b; a = a^b; System.out.println("a:" + a); System.out.println("b:" + b); } }
輸出結(jié)果:
a:6
b:5
google的一個面試題:
一個數(shù)組存放若干整數(shù),一個數(shù)出現(xiàn)奇數(shù)次,其余數(shù)均出現(xiàn)偶數(shù)次,找出這個出現(xiàn)奇數(shù)次的數(shù)?
上面的問題可以使用按位異或運算巧妙解決:
public class MyTestMain { public static void main(String[] args) { int[] nums = {2, 2, 3, 3, 4, 4, 5}; int returnValue = 0; for (int num : nums) { returnValue ^= num; } System.out.println(returnValue); } }
輸出結(jié)果:
5
以上就是Java中特殊運算符及其應(yīng)用詳解的詳細內(nèi)容,更多關(guān)于Java特殊運算符的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
MyEclipse+Tomcat+MAVEN+SVN項目完整環(huán)境搭建(圖文教程)
這篇文章主要介紹了MyEclipse+Tomcat+MAVEN+SVN項目完整環(huán)境搭建(圖文教程),非常具有實用價值,需要的朋友可以參考下2017-12-12SpringbootJPA分頁 PageRequest過時的替代方法
這篇文章主要介紹了SpringbootJPA分頁 PageRequest過時的替代方法,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-06-06