詳談Java中的二進(jìn)制及基本的位運(yùn)算
二進(jìn)制是計(jì)算技術(shù)中廣泛采用的一種數(shù)制。二進(jìn)制數(shù)據(jù)是用0和1兩個(gè)數(shù)碼來(lái)表示的數(shù)。它的基數(shù)為2,進(jìn)位規(guī)則是“逢二進(jìn)一”,借位規(guī)則是“借一當(dāng)二”,由18世紀(jì)德國(guó)數(shù)理哲學(xué)大師萊布尼茲發(fā)現(xiàn)。當(dāng)前的計(jì)算機(jī)系統(tǒng)使用的基本上是二進(jìn)制系統(tǒng),數(shù)據(jù)在計(jì)算機(jī)中主要是以補(bǔ)碼的形式存儲(chǔ)的。計(jì)算機(jī)中的二進(jìn)制則是一個(gè)非常微小的開(kāi)關(guān),用“開(kāi)”來(lái)表示1,“關(guān)”來(lái)表示0。
那么Java中的二進(jìn)制又是怎么樣的呢?讓我們一起來(lái)揭開(kāi)它神秘的面紗吧。
一、Java內(nèi)置的進(jìn)制轉(zhuǎn)換
有關(guān)十進(jìn)制轉(zhuǎn)為二進(jìn)制,和二進(jìn)制轉(zhuǎn)為十進(jìn)制這種基本的運(yùn)算方法這里就不展開(kāi)講了。
在Java中內(nèi)置了幾個(gè)方法來(lái)幫助我們進(jìn)行各種進(jìn)制的轉(zhuǎn)換。如下圖所示(以Integer整形為例,其他類型雷同):

1,十進(jìn)制轉(zhuǎn)化為其他進(jìn)制:
二進(jìn)制:Integer.toHexString(int i); 八進(jìn)制:Integer.toOctalString(int i); 十六進(jìn)制:Integer.toBinaryString(int i);
2,其他進(jìn)制轉(zhuǎn)化為十進(jìn)制:
二進(jìn)制:Integer.valueOf("0101",2).toString;
八進(jìn)制:Integer.valueOf("376",8).toString;
十六進(jìn)制:Integer.valueOf("FFFF",16).toString;
3,使用Integer類中的parseInt()方法和valueOf()方法都可以將其他進(jìn)制轉(zhuǎn)化為10進(jìn)制。
不同的是parseInt()方法的返回值是int類型,而valueOf()返回值是Integer對(duì)象。
二、基本的位運(yùn)算
二進(jìn)制可以和十進(jìn)制一樣加減乘除,但是它還有更簡(jiǎn)便的運(yùn)算方式就是——位運(yùn)算。比如在計(jì)算機(jī)中int類型的大小是32bit,可以用32位的二進(jìn)制數(shù)來(lái)表示,所以我們可以用位運(yùn)算來(lái)對(duì)int類型的數(shù)值進(jìn)行計(jì)算,當(dāng)然你也可以用平常的方法來(lái)計(jì)算一些數(shù)據(jù),這里我主要為大家介紹位運(yùn)算的方法。我們會(huì)發(fā)現(xiàn)位運(yùn)算有著普通運(yùn)算方法不可比擬的力量。更多位運(yùn)算應(yīng)用請(qǐng)轉(zhuǎn)移到我下篇博文《神奇的位運(yùn)算》
首先,看一下位運(yùn)算的基本操作符:

優(yōu)點(diǎn):
特定情況下,計(jì)算方便,速度快,被支持面廣
如果用算數(shù)方法,速度慢,邏輯復(fù)雜
位運(yùn)算不限于一種語(yǔ)言,它是計(jì)算機(jī)的基本運(yùn)算方法
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
(一)按位與&
兩位全為1,結(jié)果才為1
0&0=0;0&1=0;1&0=0;1&1=1
例如:51&5 即0011 0011 & 0000 0101 =0000 0001 因此51&5=1.
特殊用法
(1)清零。如果想將一個(gè)單元清零,即使其全部二進(jìn)制位為0,只要與一個(gè)各位都是零的數(shù)值相與,結(jié)果為零。
(2)取一個(gè)數(shù)中指定位。
例如:設(shè)X=10101110,取X的低四位,用X&0000 1111=0000 1110即可得到。
方法:找一個(gè)數(shù),對(duì)應(yīng)x要取的位,該數(shù)的對(duì)應(yīng)位為1,其余位為零,此數(shù)與x進(jìn)行“與運(yùn)算”可以得到x中的指定位。
(二)按位或 |
只要有一個(gè)為1,結(jié)果就為1。
0|0=0; 0|1=1;1|0=1;1|1=1;
例如:51|5 即0011 0011 | 0000 0101 =0011 0111 因此51|5=55
特殊用法
常用來(lái)對(duì)一個(gè)數(shù)據(jù)的某些位置1。
方法:找到一個(gè)數(shù),對(duì)應(yīng)x要置1的位,該數(shù)的對(duì)應(yīng)位為1,其余位為零。此數(shù)與x相或可使x中的某些位置1。
(三)異或 ^
兩個(gè)相應(yīng)位為“異”(值不同),則該位結(jié)果為1,否則為0
0^0=0; 0^1=1; 1^0=1; 1^1=0;
例如:51^5 即0011 0011 ^ 0000 0101 =0011 0110 因此51^5=54
特殊用法
(1) 與1相異或,使特定位翻轉(zhuǎn)
方法:找一個(gè)數(shù),對(duì)應(yīng)X要翻轉(zhuǎn)的位,該數(shù)的對(duì)應(yīng)為1,其余位為零,此數(shù)與X對(duì)應(yīng)位異或即可。
例如:X=1010 1110,使X低四位翻轉(zhuǎn),用X^0000 1111=1010 0001即可得到。
(2) 與0相異或,保留原值
例如:X^0000 0000 =1010 1110
(3)兩個(gè)變量交換值
1.借助第三個(gè)變量來(lái)實(shí)現(xiàn)
C=A;A=B;B=C;
2.利用加減法實(shí)現(xiàn)兩個(gè)變量的交換
A=A+B;B=A-B;A=A-B;
3.用位異或運(yùn)算來(lái)實(shí)現(xiàn),也是效率最高的
原理:一個(gè)數(shù)異或本身等于0 ;異或運(yùn)算符合交換律
A=A^B;B=A^B;A=A^B
(四)取反與運(yùn)算~
對(duì)一個(gè)二進(jìn)制數(shù)按位取反,即將0變?yōu)?,1變0
~1=0 ;~0=1
(五)左移<<
將一個(gè)運(yùn)算對(duì)象的各二進(jìn)制位全部左移若干位(左邊的二進(jìn)制位丟棄,右邊補(bǔ)0)
例如: 2<<1 =4 10<<1=100
若左移時(shí)舍棄的高位不包含1,則每左移一位,相當(dāng)于該數(shù)乘以2。
例如:
11(1011)<<2= 0010 1100=22
11(00000000 00000000 00000000 1011)整形32bit
(六)右移>>
將一個(gè)數(shù)的各二進(jìn)制位全部右移若干位,正數(shù)左補(bǔ)0,負(fù)數(shù)左補(bǔ)1,右邊丟棄。若右移時(shí)舍高位不是1(即不是負(fù)數(shù)),操作數(shù)每右移一位,相當(dāng)于該數(shù)除以2。
左補(bǔ)0還是補(bǔ)1得看被移數(shù)是正還是負(fù)。
例如:4>>2=4/2/2=1
-14(即1111 0010)>>2 =1111 1100=-4
(七)無(wú)符號(hào)右移運(yùn)算>>>
各個(gè)位向右移指定的位數(shù),右移后左邊空出的位用零來(lái)填充,移除右邊的位被丟棄。
例如:-14>>>2
(即11111111 11111111 11111111 11110010)>>>2
=(00111111 11111111 11111111 11111100)=1073741820
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
上述提到的負(fù)數(shù),他的二進(jìn)制位表示和正數(shù)略有不同,所以在位運(yùn)算的時(shí)候也與正數(shù)不同。
負(fù)數(shù)以其正數(shù)的補(bǔ)碼形式表示!
以上述的-14為例,來(lái)簡(jiǎn)單闡述一下原碼、反碼和補(bǔ)碼。
原 碼
一個(gè)整數(shù)按照絕對(duì)值大小轉(zhuǎn)化成的二進(jìn)制數(shù)稱為原碼
例如:00000000 00000000 00000000 00001110 是14的原碼。
反 碼
將二進(jìn)制數(shù)按位取反,所得到的新二進(jìn)制數(shù)稱為原二進(jìn)制數(shù)的反碼。
例如:將00000000 00000000 00000000 00001110 每一位取反,
得11111111 11111111 11111111 11110001
注意:這兩者互為反碼
補(bǔ) 碼
反碼加1稱為補(bǔ)碼
11111111 11111111 11111111 11110001 +1=
11111111 11111111 11111111 11110010
現(xiàn)在我們得到-14的二進(jìn)制表示,現(xiàn)在將它左移
-14(11111111 11111111 11111111 11110010)<<2 =
11111111 11111111 11111111 11001000
=?
分析:這個(gè)二進(jìn)制的首位為1,說(shuō)明是補(bǔ)碼形式,現(xiàn)在我們要將補(bǔ)碼轉(zhuǎn)換為原碼(它的正值)
跟原碼轉(zhuǎn)換為補(bǔ)碼相反,將補(bǔ)碼轉(zhuǎn)換為原碼的步驟:
補(bǔ)碼減1得到反碼:(11000111)前24位為1,此處省略
反碼取反得到原碼(即該負(fù)數(shù)的正值)(00111000)
計(jì)算正值,正值為56
取正值的相反數(shù),得到結(jié)果-56
結(jié)論:-14<<2 = -56
三、Java中進(jìn)制運(yùn)算
Java中二進(jìn)制用的多嗎?
平時(shí)開(kāi)發(fā)中“進(jìn)制轉(zhuǎn)換”和“位操作”用的不多,Java處理的是高層。
在跨平臺(tái)中用的較多,如:文件讀寫,數(shù)據(jù)通信。
來(lái)看一個(gè)場(chǎng)景:

如果客戶機(jī)和服務(wù)器都是用Java語(yǔ)言寫的程序,那么當(dāng)客戶機(jī)發(fā)送對(duì)象數(shù)據(jù),我們就可以把要發(fā)送的數(shù)據(jù)序列化seriapzable,服務(wù)器端得到序列化的數(shù)據(jù)之后就可以反序列化,讀出里面的對(duì)象數(shù)據(jù)。
隨著客戶機(jī)訪問(wèn)量的增大,我們不考慮服務(wù)器的性能,其實(shí)一個(gè)可行的方案就是把服務(wù)器的Java語(yǔ)言改成C語(yǔ)言。
C語(yǔ)言作為底層語(yǔ)言,反映速度都比Java語(yǔ)言要快,而此時(shí)如果客戶端傳遞的還是序列化的數(shù)據(jù),那么服務(wù)器端的C語(yǔ)言將無(wú)法解析,怎么辦呢?我們可以把數(shù)據(jù)轉(zhuǎn)為二進(jìn)制(0,1),這樣的話服務(wù)器就可以解析這些語(yǔ)言。

>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
Java中基本數(shù)據(jù)類型有以下四種:
Int數(shù)據(jù)類型:byte(8bit,-128~127)、short(16bit)、int(32bit)、long(64bit)
float數(shù)據(jù)類型:?jiǎn)尉龋╢loat,32bit ) 、雙精度(double,64bit)
boolean類型變量的取值有true、false(都是1bit)
char數(shù)據(jù)類型:unicode字符,16bit
對(duì)應(yīng)的類類型:
Integer、Float、Boolean、Character、Double、Short、Byte、Long
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
(一)數(shù)據(jù)類型轉(zhuǎn)為字節(jié)
例如:int型8143(00000000 00000000 00011111 11001111)
=>byte[] b=[-49,31,0,0]
第一個(gè)(低端)字節(jié):8143>>0*8 & 0xff=(11001111)=207(或有符號(hào)-49)
第二個(gè)(低端)字節(jié):8143>>1*8 &0xff=(00011111)=31
第三個(gè)(低端)字節(jié):8143>>2*8 &0xff=00000000=0
第四個(gè)(低端)字節(jié):8143>>3*8 &0xff=00000000=0
我們注意到上面的(低端)是從右往左開(kāi)始的,那什么是低端呢?我們從大小端的角度來(lái)說(shuō)明。
小端法(pttle-Endian)
低位字節(jié)排放在內(nèi)存的低地址端即該值的起始地址,高位字節(jié)排位在內(nèi)存的高地址端
大端法(Big-Endian)
高位字節(jié)排放在內(nèi)存的低地址端即該值的起始地址,低位字節(jié)排位在內(nèi)存的高地址端
為什么會(huì)有大小端模式之分呢?
這是因?yàn)樵谟?jì)算機(jī)系統(tǒng)中,我們是以字節(jié)為單位的,每個(gè)地址單元都對(duì)應(yīng)著一個(gè)字節(jié),一個(gè)字節(jié)為8bit。但是在C語(yǔ)言中除了8bit的char之外,還有16bit的short型,32bit的long型(要看具體的編譯器),另外,對(duì)于位數(shù)大于8位的處理器,例如16位或者32位的處理器,由于寄存器寬度大于一個(gè)字節(jié),那么必然存在著一個(gè)如果將多個(gè)字節(jié)安排的問(wèn)題。因此就導(dǎo)致了大端存儲(chǔ)模式和小端存儲(chǔ)模式。例如一個(gè)16bit的short型x,在內(nèi)存中的地址為0x0010,x的值為0x1122,那么0x11為高字節(jié),0x22為低字節(jié)。對(duì)于大端模式,就將0x11放在低地址中,即0x0010中,0x22放在高地址中,即0x0011中。小端模式,剛好相反。我們常用的X86結(jié)構(gòu)是小端模式,而KEIL C51則為大端模式。很多的ARM,DSP都為小端模式。有些ARM處理器還可以由硬件來(lái)選擇是大端模式還是小端模式。
例如:32bit的數(shù)0x12 34 56 78(十二進(jìn)制)
在Big-Endian模式CPU的存放方式(假設(shè)從地址0x4000開(kāi)始存放)為
|
內(nèi)存地址 |
0x4000 |
0x4001 |
0x4002 |
0x4003 |
|
存放內(nèi)容 |
0x78 |
0x56 |
0x34 |
0x12 |
在pttle-Endian模式CPU的存放方式(假設(shè)從地址0x4000開(kāi)始存放)為
|
內(nèi)存地址 |
0x4000 |
0x4001 |
0x4002 |
0x4003 |
|
存放內(nèi)容 |
0x12 |
0x34 |
0x56 |
0x78 |
(二)字符串轉(zhuǎn)化為字節(jié)
1.字符串->字節(jié)數(shù)組
String s; byte[] bs=s.getBytes();
2.字節(jié)數(shù)組->字符串
Byte[] bs=new byte[int]; String s =new String(bs);或 String s=new String(bs,encode);//encode指編碼方式,如utf-8
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
兩種類型轉(zhuǎn)化為字節(jié)的方法都介紹了,下面寫個(gè)小例子檢驗(yàn)一下:
pubpc class BtyeTest {
/*
* int整型轉(zhuǎn)為byte字節(jié)
*/
pubpc static byte[] intTOBtyes(int in){
byte[] arr=new byte[4];
for(int i=0;i<4;i++){
arr[i]=(byte)((in>>8*i) & 0xff);
}
return arr;
}
/*
* byte字節(jié)轉(zhuǎn)為int整型
*/
pubpc static int bytesToInt(byte[] arr){
int sum=0;
for(int i=0;i<arr.length;i++){
sum+=(int)(arr[i]&0xff)<<8*i;
}
return sum;
}
pubpc static void main(String[] args) {
// TODO Auto-generated method stub
byte[] arr=intTOBtyes(8143);
for(byte b:arr){
System.out.print(b+" ");
}
System.out.println();
System.out.println(bytesToInt(arr));
//字符串與字節(jié)數(shù)組
String str="云開(kāi)的立夏de博客園";
byte[] barr=str.getBytes();
String str2=new String(barr);
System.out.println("字符串轉(zhuǎn)為字節(jié)數(shù)組:");
for(byte b:barr){
System.out.print(b+" ");
}
System.out.println();
System.out.println("字節(jié)數(shù)組換位字符串:"+str2);
}
}
運(yùn)行結(jié)果:

以上這篇詳談Java中的二進(jìn)制及基本的位運(yùn)算就是小編分享給大家的全部?jī)?nèi)容了,希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
Spring Controller接收前端JSON數(shù)據(jù)請(qǐng)求方式
這篇文章主要為大家介紹了Spring Controller接收前端JSON數(shù)據(jù)請(qǐng)求方式詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-07-07
使用Logback設(shè)置property參數(shù)方式
這篇文章主要介紹了使用Logback設(shè)置property參數(shù)方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-03-03
Java實(shí)現(xiàn)SSL Socket長(zhǎng)連接方式
這篇文章主要介紹了Java實(shí)現(xiàn)SSL Socket長(zhǎng)連接方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-01-01
feign的ribbon超時(shí)配置和hystrix的超時(shí)配置說(shuō)明
這篇文章主要介紹了feign的ribbon超時(shí)配置和hystrix的超時(shí)配置說(shuō)明,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-09-09

