Java二進(jìn)制運(yùn)算符超詳細(xì)講解及擴(kuò)展知識
前言
看Java數(shù)據(jù)結(jié)構(gòu)源碼的時(shí)候發(fā)現(xiàn)很多源碼中都用到了<<和>>運(yùn)算符,果然是我太low了,用運(yùn)算符都跟不上大佬的腳步;所以打算從頭再看一次這些Java中的運(yùn)算符;
本來像寫的簡單點(diǎn)的,但是一開始梳理就收不住了… 然后就又扯出來了一大堆知識點(diǎn)…
經(jīng)過我個(gè)人的學(xué)習(xí)過程,梳理了一下相關(guān)的知識:
- 計(jì)算機(jī)存儲單元
- 原碼、反碼、補(bǔ)碼、掩碼
- 基本數(shù)據(jù)類型
- 整數(shù)的存儲
計(jì)算機(jī)存儲單元
首先區(qū)分兩個(gè)概念:
- 最小信息單元:比特(bit,二進(jìn)制位)是計(jì)算機(jī)中表示信息的最小單位,對應(yīng)二進(jìn)制中的一個(gè) “0” 或 “1”。
- 最小存儲單元:字節(jié)(byte)是計(jì)算機(jī)硬件中用于存儲數(shù)據(jù)的最小可尋址(可獨(dú)立操作)單元,通常由 8 個(gè)比特組成(1 byte = 8 bit)
1B = 8bit;
1KB = 1024B;
1MB = 1024KB;
1GB = 1024MB;
1TB = 1024GB
區(qū)分這個(gè)概念的目的是:為什么二進(jìn)制數(shù)的表示長度只能是8的倍數(shù);(反正我剛學(xué)那會是不懂)
原碼、補(bǔ)碼、反碼、掩碼
一、原碼(True Form)
定義:最直觀的二進(jìn)制表示法,由“符號位+數(shù)值位”組成,直接對應(yīng)十進(jìn)制數(shù)的正負(fù)和絕對值。
- 規(guī)則:
- 最高位為符號位:
0表示正數(shù),1表示負(fù)數(shù); - 其余位為數(shù)值位:直接表示該數(shù)的絕對值的二進(jìn)制。
- 最高位為符號位:
- 示例(以8位二進(jìn)制為例):
- 十進(jìn)制
+5的原碼:00000101(符號位0,數(shù)值位5的二進(jìn)制0000101); - 十進(jìn)制
-5的原碼:10000101(符號位1,數(shù)值位同樣是5的二進(jìn)制); - 十進(jìn)制
0的原碼有兩種:00000000(+0)和10000000(-0)。
- 十進(jìn)制
- 特點(diǎn)與問題:
- 優(yōu)點(diǎn):直觀易懂,與十進(jìn)制的對應(yīng)關(guān)系明確;
- 缺點(diǎn):
- 0的表示不唯一(+0和-0),浪費(fèi)存儲空間;
- 加減法運(yùn)算復(fù)雜(正數(shù)加負(fù)數(shù)需先比較絕對值,再做減法,符號單獨(dú)處理),不適合計(jì)算機(jī)硬件直接實(shí)現(xiàn)。
二、反碼(One’s Complement)
定義:原碼的“變形”,是從原碼過渡到補(bǔ)碼的中間形式,主要用于簡化負(fù)數(shù)的運(yùn)算。
- 規(guī)則:
- 正數(shù)的反碼 = 原碼(與原碼完全相同);
- 負(fù)數(shù)的反碼 = 原碼的“符號位不變,數(shù)值位按位取反”(0變1,1變0)。
- 示例(8位二進(jìn)制):
- 十進(jìn)制
+5的原碼:00000101→ 反碼:00000101(不變); - 十進(jìn)制
-5的原碼:10000101→ 反碼:11111010(符號位1不變,數(shù)值位0000101取反為1111010); - 十進(jìn)制
0的反碼:00000000(+0)和11111111(-0)(仍不唯一)。
- 十進(jìn)制
- 特點(diǎn)與問題:
- 優(yōu)點(diǎn):一定程度上簡化了減法運(yùn)算(減法可轉(zhuǎn)化為“加負(fù)數(shù)的反碼”);
- 缺點(diǎn):
- 0的表示仍不唯一;
- 運(yùn)算后可能需要“循環(huán)進(jìn)位”(最高位的進(jìn)位需加到最低位),硬件實(shí)現(xiàn)仍復(fù)雜,實(shí)際中很少直接使用。
三、補(bǔ)碼(Two’s Complement)
定義:計(jì)算機(jī)中實(shí)際使用的有符號整數(shù)表示法,解決了原碼和反碼的運(yùn)算缺陷,能將減法統(tǒng)一為加法。
- 規(guī)則:
- 正數(shù)的補(bǔ)碼 = 原碼(與原碼、反碼相同);
- 負(fù)數(shù)的補(bǔ)碼 = 反碼 + 1(即“原碼符號位不變,數(shù)值位取反后加1”)。
- 示例(8位二進(jìn)制):
- 十進(jìn)制
+5的補(bǔ)碼:00000101(與原碼、反碼一致); - 十進(jìn)制
-5的補(bǔ)碼:
原碼10000101→ 反碼11111010→ 反碼+1 =11111011(補(bǔ)碼); - 十進(jìn)制
0的補(bǔ)碼:00000000(唯一表示,無+0和-0之分)。
- 十進(jìn)制
- 核心優(yōu)勢:
- 0的表示唯一,節(jié)省存儲空間;
- 減法可轉(zhuǎn)化為加法:
a - b = a + (-b的補(bǔ)碼),硬件只需實(shí)現(xiàn)加法器即可,無需單獨(dú)的減法電路; - 運(yùn)算時(shí)符號位自動參與運(yùn)算,無需單獨(dú)處理符號。
- 驗(yàn)證:用補(bǔ)碼計(jì)算
5 - 3(即5 + (-3)):5的補(bǔ)碼:00000101;-3的補(bǔ)碼:原碼10000011→ 反碼11111100→ 補(bǔ)碼11111101;- 相加:
00000101 + 11111101 = 100000010(8位截?cái)嗪鬄?code>00000010,即十進(jìn)制2,正確)。
四、掩碼(Mask)
定義:一種特定的二進(jìn)制序列(通常是整數(shù)),通過與位運(yùn)算符(&、|、^)配合,實(shí)現(xiàn)對目標(biāo)二進(jìn)制數(shù)“特定位的提取、設(shè)置或清除”。
- 核心作用:精準(zhǔn)操作二進(jìn)制中的某幾位,而不影響其他位。
- 常見用法:
- 提取特定位(用
&運(yùn)算):
掩碼中需保留的位設(shè)為1,其他位設(shè)為0,與目標(biāo)數(shù)&后,僅保留目標(biāo)數(shù)中對應(yīng)掩碼1的位。
例:提取8位二進(jìn)制10110101的低4位:
目標(biāo)數(shù):10110101
掩碼:00001111(低4位為1)
結(jié)果:10110101 & 00001111 = 00000101(僅保留低4位)。 - 設(shè)置特定位為1(用
|運(yùn)算):
掩碼中需設(shè)置為1的位設(shè)為1,其他位設(shè)為0,與目標(biāo)數(shù)|后,目標(biāo)數(shù)中對應(yīng)掩碼1的位會被強(qiáng)制設(shè)為1。
例:將8位二進(jìn)制10110101的第5位(從0開始計(jì)數(shù))設(shè)為1:
目標(biāo)數(shù):10110101(第5位當(dāng)前為0)
掩碼:00100000(第5位為1)
結(jié)果:10110101 | 00100000 = 10110101(第5位變?yōu)?)。 - 清除特定位(設(shè)為0)(用
& ~掩碼運(yùn)算):
掩碼中需清除的位設(shè)為1,其他位設(shè)為0,先對掩碼取反(~),再與目標(biāo)數(shù)&,目標(biāo)數(shù)中對應(yīng)原掩碼1的位會被設(shè)為0。
例:清除8位二進(jìn)制10110101的高4位:
目標(biāo)數(shù):10110101
掩碼:11110000(高4位為1)
取反掩碼:00001111
結(jié)果:10110101 & 00001111 = 00000101(高4位被清除)。
- 提取特定位(用
- 典型應(yīng)用:權(quán)限控制(用位表示不同權(quán)限)、數(shù)據(jù)打包/解包(如協(xié)議報(bào)文解析)、硬件寄存器操作等。
Java的基本數(shù)據(jù)類型
不同基本數(shù)據(jù)類型的區(qū)別在于二進(jìn)制的“組織方式”和“長度”(即占用的比特?cái)?shù)),但本質(zhì)都是二進(jìn)制。以下是具體說明:
一、 整數(shù)類型(byte/short/int/long)
整數(shù)類型直接以二進(jìn)制補(bǔ)碼形式存儲(補(bǔ)碼是計(jì)算機(jī)中表示有符號整數(shù)的標(biāo)準(zhǔn)方式,可統(tǒng)一加減法運(yùn)算):
byte(8位):如十進(jìn)制66存儲為01000010(符號位0表示正數(shù),數(shù)值位為66的二進(jìn)制)。int(32位):如十進(jìn)制1存儲為00000000 00000000 00000000 00000001(32位補(bǔ)碼,高位補(bǔ)0)。long(64位):在int的基礎(chǔ)上擴(kuò)展到64位,高位補(bǔ)0或符號位。
二、 浮點(diǎn)類型(float/double)
浮點(diǎn)類型遵循IEEE 754標(biāo)準(zhǔn),以二進(jìn)制形式存儲,但結(jié)構(gòu)更復(fù)雜(分為符號位、指數(shù)位、尾數(shù)位):
float(32位):1位符號位 + 8位指數(shù)位 + 23位尾數(shù)位。double(64位):1位符號位 + 11位指數(shù)位 + 52位尾數(shù)位。
例如,十進(jìn)制3.14f(float類型)會被轉(zhuǎn)換為對應(yīng)的32位二進(jìn)制浮點(diǎn)格式存儲。
三、 字符類型(char)
char類型存儲Unicode字符編碼(本質(zhì)是無符號整數(shù)),以16位二進(jìn)制形式存儲:
- 例如字符
'A'的Unicode編碼是65,對應(yīng)二進(jìn)制00000000 01000001(16位)。 - 中文字符
'中'的Unicode編碼是20013,對應(yīng)二進(jìn)制01001110 00101101。
四、 布爾類型(boolean)
boolean類型比較特殊,Java規(guī)范未明確其占用的比特?cái)?shù)(不同JVM實(shí)現(xiàn)可能不同),但本質(zhì)仍是二進(jìn)制表示:
- 通常用1位二進(jìn)制表示(
0對應(yīng)false,1對應(yīng)true),但為了內(nèi)存對齊,實(shí)際可能占用1字節(jié)(8位),僅用最低位表示真假。
Java中的整數(shù)存儲
一、Java中整數(shù)的存儲:補(bǔ)碼是唯一標(biāo)準(zhǔn)
Java中所有有符號整數(shù)(byte/short/int/long)統(tǒng)一使用補(bǔ)碼存儲,不存在原碼或反碼的直接使用,這是Java為簡化運(yùn)算和硬件適配做的設(shè)計(jì):
int類型(32位):最高位為符號位,范圍-2³¹ ~ 2³¹-1,其中-2³¹(-2147483648)是特殊值,補(bǔ)碼為10000000 00000000 00000000 00000000(無對應(yīng)的原碼/反碼)。long類型(64位):同理,范圍-2?³ ~ 2?³-1,補(bǔ)碼存儲。
示例:
十進(jìn)制-5的int補(bǔ)碼計(jì)算:
原碼(符號位1+數(shù)值位5)→ 10000000 00000000 00000000 00000101
反碼(符號位不變,數(shù)值位取反)→ 11111111 11111111 11111111 11111010
補(bǔ)碼(反碼+1)→ 11111111 11111111 11111111 11111011(Java中實(shí)際存儲的形式)
二、Java中的位運(yùn)算符:直接操作二進(jìn)制補(bǔ)碼
Java支持5種位運(yùn)算符(針對整數(shù)類型),操作的是數(shù)值的補(bǔ)碼二進(jìn)制位:
| 運(yùn)算符 | 名稱 | 規(guī)則(逐位操作) | 示例(int類型) |
|---|---|---|---|
& | 按位與 | 全1為1,否則為0 | 3 & 5 → 00000011 & 00000101 = 00000001 → 1 |
| ` | ` | 按位或 | 按位或 |
^ | 按位異或 | 不同為1,相同為0 | 3 ^ 5 → 00000011 ^ 00000101 = 00000110 → 6 |
~ | 按位取反 | 0變1,1變0(補(bǔ)碼取反) | ~3 → ~00000011 = 11111100(補(bǔ)碼)→ -4 |
<< | 左移 | 左移n位,右補(bǔ)0 | 3 << 2 → 00000011 << 2 = 00001100 → 12 |
>> | 算術(shù)右移 | 右移n位,左補(bǔ)符號位(正數(shù)補(bǔ)0,負(fù)數(shù)補(bǔ)1) | -8 >> 1 → 11111000 >> 1 = 11111100 → -4 |
>>> | 無符號右移 | 右移n位,左補(bǔ)0(忽略符號位) | -1 >>> 1 → 11111111... >>> 1 = 01111111... → 2147483647 |
關(guān)鍵特性:
- 類型提升:對
byte/short進(jìn)行位運(yùn)算時(shí),會先自動提升為int(32位),結(jié)果也是int。
例:byte b = 3; byte c = (byte)(b << 1);(需強(qiáng)制轉(zhuǎn)型,否則結(jié)果為int)。 - 移位位數(shù)取模:移位位數(shù)若超過類型位數(shù)(如
int移32位),會對位數(shù)取模(int移33位 = 移1位,33 % 32 = 1)。
三、掩碼在Java中的典型應(yīng)用
掩碼(mask)結(jié)合位運(yùn)算,在Java中常用于權(quán)限控制、數(shù)據(jù)解析、狀態(tài)標(biāo)記等場景:
1. 權(quán)限控制(用二進(jìn)制位表示不同權(quán)限)
// 定義權(quán)限掩碼(每個(gè)權(quán)限對應(yīng)1位)
public class Permission {
public static final int READ = 1 << 0; // 0001(1):讀權(quán)限
public static final int WRITE = 1 << 1; // 0010(2):寫權(quán)限
public static final int EXEC = 1 << 2; // 0100(4):執(zhí)行權(quán)限
public static void main(String[] args) {
int permissions = READ | WRITE; // 組合權(quán)限:0011(3)
// 檢查是否有寫權(quán)限(用&)
boolean canWrite = (permissions & WRITE) != 0; // true
// 添加執(zhí)行權(quán)限(用|)
permissions |= EXEC; // 0111(7)
// 移除讀權(quán)限(用& ~)
permissions &= ~READ; // 0110(6)
}
}
2. 解析二進(jìn)制協(xié)議數(shù)據(jù)(提取特定字段)
假設(shè)某協(xié)議用16位二進(jìn)制表示“命令(高8位)+ 參數(shù)(低8位)”:
short data = 0x1234; // 二進(jìn)制:00010010 00110100(高8位0x12,低8位0x34) // 提取高8位(命令):右移8位,并用0xFF掩碼保留低8位 int command = (data >> 8) & 0xFF; // 0x12(18) // 提取低8位(參數(shù)):用0xFF掩碼保留低8位 int param = data & 0xFF; // 0x34(52)
四、注意事項(xiàng)
- 溢出問題:位運(yùn)算可能導(dǎo)致溢出(如
int最大值左移1位變?yōu)樨?fù)數(shù)),但Java不拋異常,直接按補(bǔ)碼截?cái)唷?/li> boolean不支持位運(yùn)算:boolean類型不能參與位運(yùn)算(需用&&/||邏輯運(yùn)算)。- 浮點(diǎn)數(shù)無位運(yùn)算:
float/double不支持位運(yùn)算符(底層是IEEE 754浮點(diǎn)格式,需先轉(zhuǎn)整數(shù)再操作)。
二進(jìn)制運(yùn)算符應(yīng)用場景
Java中除了位移運(yùn)算符(<<、>>、>>>),還有另外4種核心二進(jìn)制運(yùn)算符:按位與(&)、按位或(|)、按位異或(^)、按位取反(~)。它們直接對整數(shù)的補(bǔ)碼二進(jìn)制位進(jìn)行逐位操作,廣泛用于位級數(shù)據(jù)處理、權(quán)限控制、編碼解碼等場景。
一、按位與(&):全1為1,否則為0
規(guī)則:兩個(gè)操作數(shù)的對應(yīng)二進(jìn)制位進(jìn)行比較,只有當(dāng)兩個(gè)位都為1時(shí),結(jié)果位才為1;其他情況(0&0、0&1、1&0)結(jié)果位為0。
示例(以8位二進(jìn)制為例):
計(jì)算 3 & 5:
- 3的補(bǔ)碼:
00000011 - 5的補(bǔ)碼:
00000101 - 逐位與運(yùn)算:
00000011 & 00000101 ----------- 00000001 // 結(jié)果為1(十進(jìn)制)
核心應(yīng)用場景:
- 提取/保留特定位(配合掩碼):
用掩碼(mask)中為1的位“保留”目標(biāo)數(shù)的對應(yīng)位,為0的位“清除”對應(yīng)位。
例:提取int類型的低8位(取最后一個(gè)字節(jié)):
int num = 0x123456; // 二進(jìn)制:00010010 00110100 01010110 int mask = 0xFF; // 掩碼:00000000 00000000 11111111 int result = num & mask; // 0x56(僅保留低8位)
- 判斷奇偶性:
一個(gè)數(shù)的二進(jìn)制末位為1則是奇數(shù),為0則是偶數(shù)。通過與1按位與可快速判斷:
boolean isOdd = (num & 1) == 1; // 末位為1 → 奇數(shù)
- 清零操作:
與全0掩碼按位與,可將目標(biāo)數(shù)清零(num & 0 → 0)。
二、按位或(|):有1為1,全0為0
規(guī)則:兩個(gè)操作數(shù)的對應(yīng)二進(jìn)制位進(jìn)行比較,只要有一個(gè)位為1,結(jié)果位就為1;只有當(dāng)兩個(gè)位都為0時(shí),結(jié)果位才為0。
示例:
計(jì)算 3 | 5:
- 3的補(bǔ)碼:
00000011 - 5的補(bǔ)碼:
00000101 - 逐位或運(yùn)算:
00000011 | 00000101 ----------- 00000111 // 結(jié)果為7(十進(jìn)制)
核心應(yīng)用場景:
- 設(shè)置特定位為1(配合掩碼):
用掩碼中為1的位“強(qiáng)制設(shè)置”目標(biāo)數(shù)的對應(yīng)位為1,其他位保持不變。
例:將int的第3位(從0開始)設(shè)為1:
int num = 0b1001; // 二進(jìn)制1001(9) int mask = 1 << 3; // 掩碼1000(第3位為1) int result = num | mask; // 1001 | 1000 = 1001(若原位為0則變?yōu)?)
- 組合權(quán)限/狀態(tài):
用不同位表示不同權(quán)限(如READ=1<<0、WRITE=1<<1),通過|組合多個(gè)權(quán)限:
int permissions = READ | WRITE | EXEC; // 組合讀、寫、執(zhí)行權(quán)限
- 填充數(shù)據(jù):
將低n位填充為1(如num | ((1 << n) - 1)),用于范圍限制。
三、按位異或(^):不同為1,相同為0
規(guī)則:兩個(gè)操作數(shù)的對應(yīng)二進(jìn)制位進(jìn)行比較,若兩個(gè)位不同(0和1),結(jié)果位為1;若相同(0和0或1和1),結(jié)果位為0。
示例:
計(jì)算 3 ^ 5:
- 3的補(bǔ)碼:
00000011 - 5的補(bǔ)碼:
00000101 - 逐位異或運(yùn)算:
00000011 ^ 00000101 ----------- 00000110 // 結(jié)果為6(十進(jìn)制)
核心應(yīng)用場景:
- 翻轉(zhuǎn)特定位:
用掩碼中為1的位“翻轉(zhuǎn)”目標(biāo)數(shù)的對應(yīng)位(0變1,1變0),為0的位保持不變。
例:翻轉(zhuǎn)int的低4位:
int num = 0b1010; // 1010 int mask = 0b1111; // 掩碼1111 int result = num ^ mask; // 1010 ^ 1111 = 0101(低4位翻轉(zhuǎn))
- 不借助臨時(shí)變量交換兩個(gè)數(shù):
利用異或的特性(a ^ a = 0,a ^ 0 = a)實(shí)現(xiàn)無臨時(shí)變量交換:
int a = 3, b = 5; a = a ^ b; // a = 3^5 = 6 b = a ^ b; // b = 6^5 = 3(原a的值) a = a ^ b; // a = 6^3 = 5(原b的值)
- 簡單加密/校驗(yàn):
對數(shù)據(jù)與密鑰異或?qū)崿F(xiàn)加密,解密時(shí)再次異或相同密鑰:
int data = 0x1234; int key = 0x5678; int encrypted = data ^ key; // 加密 int decrypted = encrypted ^ key; // 解密(恢復(fù)原數(shù)據(jù))
四、按位取反(~):0變1,1變0
規(guī)則:對操作數(shù)的每一位二進(jìn)制位進(jìn)行“取反”(0→1,1→0),包括符號位。結(jié)果為“操作數(shù)的補(bǔ)碼取反”(對int是32位取反,long是64位取反)。
示例(32位int):
計(jì)算 ~3:
- 3的補(bǔ)碼:
00000000 00000000 00000000 00000011 - 按位取反:
11111111 11111111 11111111 11111100(補(bǔ)碼) - 轉(zhuǎn)換為十進(jìn)制:
-4(補(bǔ)碼取反后為負(fù)數(shù),計(jì)算方式見補(bǔ)碼規(guī)則)
核心應(yīng)用場景:
- 生成反掩碼:
對掩碼取反得到“反掩碼”,用于清除特定位(配合&運(yùn)算)。
例:清除int的高16位:
int num = 0x12345678; int mask = 0xFFFF0000; // 高16位為1的掩碼 int result = num & ~mask; // 清除高16位,保留低16位(0x5678)
- 計(jì)算負(fù)數(shù)的補(bǔ)碼:
取反加1是求負(fù)數(shù)補(bǔ)碼的方法(~n + 1 = -n),例:~3 + 1 = -3。 - 位運(yùn)算中的“非”操作:
對布爾相關(guān)的位狀態(tài)取反(如flag = ~flag & 1,將0和1互轉(zhuǎn))。
五、左移(<<):高效的“乘以2?”運(yùn)算
左移的核心特性是:無溢出時(shí),a << n** 等價(jià)于 **a × 2?,且位操作比乘法指令執(zhí)行更快(硬件層面僅需移位,無需復(fù)雜計(jì)算)。因此,左移主要用于需要“快速放大數(shù)值”或“按2的冪次調(diào)整范圍”的場景。
1. 性能敏感的乘法計(jì)算
在高頻計(jì)算場景(如游戲引擎、實(shí)時(shí)數(shù)據(jù)處理)中,用左移替代× 2?可提升性能。
例:
- 計(jì)算
a × 8(即a × 2³):a << 3比a * 8執(zhí)行更快; - 圖形渲染中計(jì)算像素地址(如每行像素?cái)?shù)為
width,第y行的起始地址可表示為baseAddress + (y << log2(pixelSize)),通過左移快速計(jì)算偏移量)。
2. 生成掩碼或標(biāo)志位
左移可快速生成“僅某一位為1”的二進(jìn)制掩碼(用于位運(yùn)算中的權(quán)限控制、狀態(tài)標(biāo)記)。
例:
// 生成第n位為1的掩碼(如第3位:1000) int mask = 1 << 3; // 二進(jìn)制1000,對應(yīng)十進(jìn)制8
這是權(quán)限控制、狀態(tài)位設(shè)計(jì)的基礎(chǔ)(如前面提到的READ = 1 << 0、WRITE = 1 << 1)。
3. 調(diào)整數(shù)值范圍(縮放)
在需要按2的冪次縮放數(shù)據(jù)時(shí)(如將小范圍數(shù)值映射到更大范圍),左移是簡潔的實(shí)現(xiàn)方式。
例:將8位灰度值(0~255)映射到32位ARGB顏色的紅色通道(需左移16位):
int gray = 0x80; // 8位灰度值(128) int redChannel = gray << 16; // 映射到ARGB的紅色通道(0x800000)
六、算術(shù)右移(>>):有符號數(shù)的“除以2?”運(yùn)算
算術(shù)右移的核心特性是:a >> n** 等價(jià)于 a ÷ 2?(向下取整),且保持符號不變**(正數(shù)仍為正,負(fù)數(shù)仍為負(fù))。因此,它適合處理“有符號數(shù)的縮小”或“需要保留符號的位移”場景。
1. 有符號數(shù)的除法優(yōu)化
與左移對應(yīng),算術(shù)右移可替代÷ 2?,且比除法指令更快,尤其適合負(fù)數(shù)場景(保證結(jié)果仍為負(fù)數(shù))。
例:
- 計(jì)算
a ÷ 4(即a ÷ 2²):a >> 2比a / 4更高效; - 負(fù)數(shù)除法:
-8 >> 1結(jié)果為-4(正確),而若用無符號右移會得到正數(shù)(錯(cuò)誤)。
2. 二分查找中的中間索引計(jì)算
在二分查找等算法中,計(jì)算中間索引(mid = (left + right) / 2)時(shí),用算術(shù)右移可避免溢出并提升效率。
例:
int left = 0, right = 1000; int mid = (left + right) >> 1; // 等價(jià)于 (left + right) / 2,結(jié)果為500
(注:更嚴(yán)謹(jǐn)?shù)膶懛ㄊ?code>left + ((right - left) >> 1),避免left + right溢出,但核心仍依賴右移的除法特性。)
3. 音頻/視頻的音量調(diào)整(按比例縮小)
在多媒體處理中,音量調(diào)整本質(zhì)是對音頻采樣值(有符號整數(shù))按比例縮小,算術(shù)右移可高效實(shí)現(xiàn)“除以2?”的衰減。
例:將音量衰減為原來的1/2(右移1位):
short sample = 32767; // 音頻采樣值(有符號16位) short attenuated = (short) (sample >> 1); // 16383(約為32767/2)
七、無符號右移(>>>):無符號數(shù)據(jù)處理與位提取
無符號右移的核心特性是:左側(cè)補(bǔ)0,不考慮符號位,將數(shù)值視為“無符號整數(shù)”處理。因此,它適合處理“無符號數(shù)據(jù)”或“需要提取二進(jìn)制位”的場景(忽略符號影響)。
1. 解析二進(jìn)制協(xié)議/文件格式
網(wǎng)絡(luò)協(xié)議(如TCP/UDP報(bào)文頭)、文件格式(如圖片、視頻)的字段常以“無符號二進(jìn)制位”存儲(如長度、標(biāo)志),無符號右移可正確提取這些字段。
例:解析一個(gè)32位無符號整數(shù)的高16位和低16位:
int unsignedInt = 0x12345678; // 32位無符號數(shù)(十六進(jìn)制) int high16 = unsignedInt >>> 16; // 提取高16位:0x1234 int low16 = unsignedInt & 0xFFFF; // 提取低16位:0x5678
2. 處理哈希值或UUID(無符號場景)
哈希值(如Object.hashCode())、UUID等通常被視為無符號數(shù),無符號右移可避免符號位干擾,正確處理這些值的位操作。
例:將32位哈希值轉(zhuǎn)換為0~1的浮點(diǎn)數(shù)(需視為無符號數(shù)):
int hashCode = "test".hashCode(); float ratio = (hashCode >>> 1) / (float) (1 << 31); // 無符號右移后計(jì)算比例
3. 生成非負(fù)整數(shù)(消除符號位影響)
當(dāng)需要將負(fù)數(shù)轉(zhuǎn)換為非負(fù)數(shù)(僅關(guān)注其補(bǔ)碼的二進(jìn)制位模式)時(shí),無符號右移可直接“抹除”符號位(左側(cè)補(bǔ)0)。
例:將-1(32位全1)轉(zhuǎn)換為最大非負(fù)整數(shù):
int negative = -1; int positive = negative >>> 0; // 結(jié)果為2147483647(32位無符號最大值)
4. 位逆序或循環(huán)移位(底層算法)
在密碼學(xué)、編碼算法中,需要對二進(jìn)制位進(jìn)行逆序或循環(huán)移位,無符號右移可配合其他位運(yùn)算實(shí)現(xiàn)(避免符號位干擾)。
例:將8位二進(jìn)制位逆序(如10110010 → 01001101):
byte b = (byte) 0xB2; // 二進(jìn)制10110010
int reversed = 0;
for (int i = 0; i < 8; i++) {
reversed = (reversed << 1) | ((b >>> i) & 1); // 無符號右移提取每一位
}
// reversed結(jié)果為0x4D(二進(jìn)制01001101)
總結(jié)
三種位移運(yùn)算符的應(yīng)用場景可歸納為:
| 運(yùn)算符 | 核心特性 | 典型場景 |
|---|---|---|
& | 全1為1,否則為0 | 提取特定位、判斷奇偶、清零 |
| ` | ` | 有1為1,全0為0 |
^ | 不同為1,相同為0 | 翻轉(zhuǎn)特定位、交換變量、簡單加密 |
~ | 0變1,1變0 | 生成反掩碼、計(jì)算補(bǔ)碼、位狀態(tài)取反 |
<< | 等價(jià)于× 2?,快速放大 | 性能敏感的乘法、生成掩碼、數(shù)值范圍調(diào)整 |
>> | 等價(jià)于÷ 2?,保持符號 | 有符號數(shù)除法、二分查找、音量調(diào)整 |
>>> | 無符號處理,左側(cè)補(bǔ)0 | 二進(jìn)制協(xié)議解析、哈希值處理、位提取 |
理解這些場景的關(guān)鍵是:根據(jù)是否需要“保留符號”“處理無符號數(shù)據(jù)”或“追求運(yùn)算效率”選擇合適的位移方式,充分利用位操作的高性能特性。
補(bǔ)充:反碼循環(huán)進(jìn)位
在反碼的加法運(yùn)算中,“循環(huán)進(jìn)位”是一個(gè)特殊的處理規(guī)則,指的是當(dāng)兩個(gè)反碼相加時(shí),若最高位(符號位)產(chǎn)生進(jìn)位,則需要將這個(gè)進(jìn)位“循環(huán)”到結(jié)果的最低位(即把進(jìn)位值1加到結(jié)果的最低位),以保證運(yùn)算結(jié)果的正確性。
為什么會出現(xiàn)循環(huán)進(jìn)位?
反碼的核心問題是0的表示不唯一(存在+0和-0),這導(dǎo)致反碼的加法運(yùn)算可能產(chǎn)生“虛假進(jìn)位”。如果直接丟棄最高位的進(jìn)位,會導(dǎo)致結(jié)果錯(cuò)誤,因此需要通過“循環(huán)進(jìn)位”修正。
舉例說明循環(huán)進(jìn)位的過程
以8位反碼為例,計(jì)算 3 + (-1):
- 先寫出兩數(shù)的反碼:
- 3的反碼:
00000011(正數(shù)反碼=原碼) - -1的原碼:
10000001→ 反碼(符號位不變,數(shù)值位取反):11111110
- 3的反碼:
- 反碼相加:
00000011 (3的反碼) + 11111110 (-1的反碼) ----------- 100000001 (結(jié)果,最高位產(chǎn)生進(jìn)位1)
- 處理循環(huán)進(jìn)位:
最高位的進(jìn)位“1”不能丟棄,需加到結(jié)果的最低位:
00000001 (去掉最高位進(jìn)位后的結(jié)果) + 1 (循環(huán)進(jìn)位的1) ----------- 00000010 (最終結(jié)果,對應(yīng)十進(jìn)制2,正確)
若不循環(huán)進(jìn)位會怎樣?
如果直接丟棄最高位的進(jìn)位,上面的結(jié)果會是 00000001(對應(yīng)十進(jìn)制1),與正確結(jié)果2不符??梢?,循環(huán)進(jìn)位是反碼加法中修正錯(cuò)誤的必要步驟。
總結(jié)
- 循環(huán)進(jìn)位:反碼加法中,最高位產(chǎn)生的進(jìn)位需加到結(jié)果的最低位,是反碼為解決“0的雙重表示”導(dǎo)致的運(yùn)算錯(cuò)誤而設(shè)計(jì)的規(guī)則。
- 局限性:這種處理增加了硬件實(shí)現(xiàn)的復(fù)雜度,這也是反碼僅作為“過渡形式”存在,而計(jì)算機(jī)最終采用補(bǔ)碼(無需循環(huán)進(jìn)位)的重要原因。
到此這篇關(guān)于Java二進(jìn)制運(yùn)算符超詳細(xì)講解及擴(kuò)展知識的文章就介紹到這了,更多相關(guān)Java二進(jìn)制運(yùn)算符內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Java?list如何實(shí)現(xiàn)將指定元素排在第一位
這篇文章主要為大家詳細(xì)介紹了Java?list中如何實(shí)現(xiàn)將指定元素排在第一位,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下2025-02-02
MyBatisPlus?TypeHandler自定義字段類型轉(zhuǎn)換Handler
這篇文章主要為大家介紹了MyBatisPlus?TypeHandler自定義字段類型轉(zhuǎn)換Handler示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-08-08
解決IDEA開發(fā)工具右側(cè)沒有Maven工具欄的問題
這篇文章主要給大家解決了IDEA開發(fā)工具右側(cè)沒有Maven工具欄的問題,文中有詳細(xì)的解決步驟,如果有遇到一樣問題的小伙伴,可以參考閱讀本文2023-09-09
Spring Boot 中的 @ConditionalOnBean 注解場景分析
本文詳細(xì)介紹了Spring Boot中的@ConditionalOnBean注解的使用場景、原理和基本用法,通過多個(gè)示例,展示了如何使用該注解根據(jù)Bean是否存在來動態(tài)地注冊或跳過特定的Bean,感興趣的朋友一起看看吧2025-03-03
Java基于高精度整型實(shí)現(xiàn)fibonacci數(shù)列的方法
這篇文章主要介紹了Java基于高精度整型實(shí)現(xiàn)fibonacci數(shù)列的方法,是比較典型的算法,需要的朋友可以參考下2014-09-09

