<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    amp@java

      BlogJava :: 首頁(yè) :: 新隨筆 :: 聯(lián)系 :: 聚合  :: 管理 ::
      99 隨筆 :: 0 文章 :: 228 評(píng)論 :: 0 Trackbacks
    當(dāng)讀寫二進(jìn)制文件,或者要把非標(biāo)準(zhǔn)長(zhǎng)度的整數(shù)與標(biāo)準(zhǔn)長(zhǎng)度的整數(shù)互相轉(zhuǎn)換時(shí),就要用到大量的位操作,雖然看起來(lái)很簡(jiǎn)單,實(shí)際上里面卻有很多細(xì)節(jié)很容易出錯(cuò)。

    首先,Java有些標(biāo)準(zhǔn)跟C/C++是不同的:

    1、Java采用高字節(jié)在前的方式讀寫數(shù)據(jù),例如要把一個(gè)4字節(jié)的int數(shù)值寫入文件時(shí),它是按照從高字節(jié)到低字節(jié)的順序?qū)懭氲模x取的時(shí)候也是這樣讀出來(lái)。
    而C/C++則采用平臺(tái)相關(guān)的方式,在Windows平臺(tái)采用低字節(jié)在前的方式,在Linux/Unix平臺(tái)則采用高字節(jié)在前的方式。
    如果Java要讀取C/C++創(chuàng)建的二進(jìn)制文件,就要注意這個(gè)問(wèn)題,最好先搞清楚原來(lái)的文件是采用哪種方式創(chuàng)建的。網(wǎng)絡(luò)通信也要注意。

    2、Java沒有無(wú)符號(hào)數(shù),無(wú)論byte,short,int,long都是有符號(hào)整數(shù),而C/C++有個(gè)unsigned關(guān)鍵字可以設(shè)置一個(gè)數(shù)值為無(wú)符號(hào)數(shù)。

    3、Java的整數(shù)基本數(shù)據(jù)類型就是byte,short,int,long這幾個(gè),長(zhǎng)度分別為1,2,4,8字節(jié),C/C++可以用typedef定義各種數(shù)據(jù)類型。

    第二,Java是采用補(bǔ)碼來(lái)存放整數(shù)的。
    有時(shí)候覺得補(bǔ)碼的定義有些奇怪,實(shí)際上可以這樣理解:

    把一個(gè)整數(shù)從0一直往上加1,加到溢出就變成了負(fù)數(shù)的最小值,然后再繼續(xù)加1,最后又能回到0,實(shí)際上就是一個(gè)輪回。
    例如一個(gè)byte類型的整數(shù),一共有8位,能表示256個(gè)數(shù)值,采用補(bǔ)碼的話數(shù)值范圍就是-128~127,表示方法如下:
    0        0000 0000
    1        0000 0001
    .
    .
    126    0111 1110
    127    0111 1111
    -128   1000 0000
    -127   1000 0001
    .
    .
    -1       1111 1111
    0         0000 0000

    第三、不同長(zhǎng)度的整數(shù)轉(zhuǎn)換。
    如果是從較短的數(shù)轉(zhuǎn)成較長(zhǎng)的數(shù),很簡(jiǎn)單,如果是正數(shù)就在高字節(jié)補(bǔ)0,如果是負(fù)數(shù)就在高字節(jié)補(bǔ)1。
    例如byte的127轉(zhuǎn)為short的127:
    byte:0111 1111
    short:0000 0000 0111 0111
    byte的-127轉(zhuǎn)為short的-127
    byte:1000 0001
    short:1111 1111 1000 0001
    如果是從較長(zhǎng)的數(shù)轉(zhuǎn)成較短的數(shù),實(shí)際上就是把高位都截?cái)嗔耍赞D(zhuǎn)出來(lái)的數(shù)值可能完全不是一回事了。
    例如short的256轉(zhuǎn)為byte:
    short:0000 0001 0000 0000
    byte: 0000 0000
    把256變成了0
    short的-255轉(zhuǎn)成byte:
    short:1111 1111 0000 0001
    byte:0000 0001
    把-255變成了1

    第四、位運(yùn)算操作符及它們的優(yōu)先級(jí)
    Java的位運(yùn)算操作符包括:~非,|按位或,&按位與,^按位異或,<<左移,>>右移,>>>右移左側(cè)補(bǔ)0
    各種運(yùn)算符的優(yōu)先級(jí)如下表所示:
    優(yōu)先級(jí)
    運(yùn)算符
    結(jié)合性
    1
    () [] .
    從左到右
    2
    ! +(正) -(負(fù)) ~ ++ --
    從右向左
    3
    * / %
    從左向右
    4
    +(加) -(減)
    從左向右
    5
    << >> >>>
    從左向右
    6
    < <= > >= instanceof
    從左向右
    7
    == !=
    從左向右
    8
    &(按位與)
    從左向右
    9
    ^
    從左向右
    10
    |
    從左向右
    11
    &&
    從左向右
    12
    ||
    從左向右
    13
    ?:
    從右向左
    14
    = += -= *= /= %= &= |= ^= ~= <<= >>= >>>=
    從右向左
    根據(jù)該表可以看到,位運(yùn)算操作符的優(yōu)先級(jí)各有不同,分別為:
    1、~
    2、>> << >>>
    3、&
    4、^
    5、|
    另外需要特別注意的是,除了~,其他位運(yùn)算操作的優(yōu)先級(jí)都低于加減,所以要記得以下語(yǔ)句是返回32而不是7!
    1<<2+3
    還有就是&、^、|的優(yōu)先級(jí)都是低于邏輯操作符的,因此下面的語(yǔ)句會(huì)編譯出錯(cuò),幸好Java不像C那樣對(duì)所有大于1的值都認(rèn)為是真,否則下面的語(yǔ)句也能編譯通過(guò),但可能與你的意圖不太一樣,可能調(diào)試半天才發(fā)現(xiàn)。
    if(3&1>0)
    如果記不清楚,還是按照你的意圖加上括號(hào)最保險(xiǎn)。

    第五、字節(jié)數(shù)組與整數(shù)之間的轉(zhuǎn)換
    為了把一個(gè)整數(shù)存入文件,或者從文件中讀取一個(gè)整數(shù),需要經(jīng)常在字節(jié)數(shù)組和整數(shù)之間轉(zhuǎn)換,這個(gè)過(guò)程要用到大量的位運(yùn)算。
    首先需要記住的是,在參與所有運(yùn)算前,Java都會(huì)把byte、short類型的值都轉(zhuǎn)換成int,然后再對(duì)轉(zhuǎn)換后的int進(jìn)行操作。例如下面的語(yǔ)句會(huì)編譯出錯(cuò):
    byte a=10,b=20,c;
    c=a+b;

    因?yàn)閍和b在相加前都被轉(zhuǎn)成了int,最后得到的結(jié)果是個(gè)int類型的值,如果要賦給byte類型的c,必須顯式地進(jìn)行類型轉(zhuǎn)換,即把第二句改為:
    c=(byte)(a+b)

    這一點(diǎn)很關(guān)鍵,因?yàn)閷?duì)于一個(gè)最高位為1的byte類型的整數(shù)(負(fù)數(shù)),在運(yùn)算之前它會(huì)被強(qiáng)制轉(zhuǎn)換成int類型,根據(jù)上面所說(shuō)的第三點(diǎn),其實(shí)就是往前面的三個(gè)高字節(jié)補(bǔ)上1,這樣一來(lái),它在參與位運(yùn)算的過(guò)程中,就不僅僅是它本身的8個(gè)bit參與了,實(shí)際上連前3個(gè)字節(jié)的24個(gè)bit(均為1)也參與了。例如有一個(gè)整數(shù)i=1082163328,它的二進(jìn)制表示為:
    01000000 10000000 10000000 10000000
    分為4個(gè)字節(jié)存儲(chǔ),除了第一個(gè)字節(jié)是正數(shù)外,其余3個(gè)字節(jié)均為負(fù)數(shù)。假如用a代表最高字節(jié)的值,用b代表其他三個(gè)字節(jié)的值,如果按照通常的理解,你可能會(huì)這樣得到i的值:
    i=(a<<24)+(b<<16)+(b<<8)+b

    如果a和b都是正數(shù),上面的等式是成立的,但是在這個(gè)例子里,卻是錯(cuò)的,因?yàn)樯鲜街械腶和b都已經(jīng)被強(qiáng)制轉(zhuǎn)換成了int類型再參加運(yùn)算,實(shí)際上
    a=00000000 00000000 00000000 01000000
    b=11111111 11111111 11111111 10000000
    i=01000000 00000000 00000000 00000000+11111111 10000000 00000000 00000000+11111111 11111111 10000000 00000000+11111111 11111111 11111111 10000000
    最后得到的結(jié)果是1065320320,不是原來(lái)的值了。
    為了不讓byte在強(qiáng)制轉(zhuǎn)換成int的過(guò)程加入了我們不想要的高位1,我們需要把它跟0xff進(jìn)行與操作,i的值應(yīng)該這樣運(yùn)算:
    = ( ( a& 0xff ) << 24 ) +( ( b & 0xff ) << 16 ) + ( ( b & 0xff ) << 8 ) + ( b & 0xff )

    注意,因?yàn)?amp;和<<的優(yōu)先級(jí)都低于+,所以上面的括號(hào)是不能少的。不過(guò)由于跟0xff與操作之后,其余24位都變成了0,因此可以把+改為|操作,因?yàn)槿魏沃蹬c0進(jìn)行或操作都得到本身:
    = ( a & 0xff ) << 24 | ( b & 0xff ) << 16 | ( b & 0xff ) << 8 | ( b & 0xff )

    由于<<的優(yōu)先級(jí)高于|,所以省了一些括號(hào)。最高字節(jié)可以不與0xff進(jìn)行與操作,因?yàn)樗D(zhuǎn)換成int后左邊增加的3個(gè)字節(jié)都在左移24位時(shí)被去掉了:
    = a << 24 | ( b & 0xff ) << 16 | ( b & 0xff ) << 8 | ( b & 0xff )


    把int轉(zhuǎn)為字節(jié)數(shù)組的時(shí)候比較簡(jiǎn)單,直接右移截?cái)嗉纯桑?/span>
    byte[] b = new byte[4];
    b[0= (byte) (i >> 24);
    b[1= (byte) (i >> 16);
    b[2= (byte) (i >> 8);
    b[3= (byte) i;


    第六、非標(biāo)準(zhǔn)長(zhǎng)度整數(shù)的存儲(chǔ)和讀取
    假如有兩個(gè)變量,他們的值可以用12個(gè)bit來(lái)表示,如果我們用16bit的short類型來(lái)表示一個(gè)變量,那么兩個(gè)變量就需要4個(gè)字節(jié),而實(shí)際上它們只需要3個(gè)字節(jié)就能表示出來(lái),如果存儲(chǔ)空間比較有限,寫入文件時(shí)可以把它們存放在3個(gè)字節(jié)里面,但是讀寫過(guò)程就需要進(jìn)行轉(zhuǎn)換。
    在內(nèi)存里,它們都是標(biāo)準(zhǔn)的數(shù)據(jù)類型:
    short a,b;

    寫入文件時(shí),我們用第一個(gè)字節(jié)和第二個(gè)字節(jié)的前半部分來(lái)表示a,把第二個(gè)字節(jié)的后半部分和第三個(gè)字節(jié)來(lái)表示b,即:
    1:xxxx xxxx
    2:xxxx yyyy
    3:yyyy yyyy
    x和y都表示一個(gè)bit,分別用來(lái)存放a和b。寫入時(shí)先把a(bǔ)和b轉(zhuǎn)為字節(jié)數(shù)組:
    byte[] out = new byte[3];
    out[
    0= (byte) ( a >> 4 );//把a(bǔ)的高8位放在第一個(gè)字節(jié)
    out[1= (byte) ( a << 4 );//先把a(bǔ)左移四位,在右邊補(bǔ)上4個(gè)0,第二個(gè)字節(jié)的高4位就是a的低4位了,第二個(gè)字節(jié)的高4位已經(jīng)生成,低4位還是0
    out[1|= (byte) ( b >> 8 & 0x0f );//b右移8位,并與0x0f進(jìn)行與操作,實(shí)際上就只保留了b的高4位,并且是在字節(jié)的低4位上,跟第二步得到的字節(jié)進(jìn)行或操作,就生成了第二個(gè)字節(jié)
    out[2= (byte) b;//把b的高4位截?cái)嗑偷玫搅说?位
    然后再把這個(gè)字節(jié)數(shù)組寫入文件,就可以用3個(gè)字節(jié)表示兩個(gè)整數(shù)了。
    讀?。?/span>
    =(short)( (out[0& 0xff<< 4 | ( out[1& 0xf0 )>>4);
    = (short)((out[1& 0x0f<< 8 | ( out[2& 0xff));
    posted on 2012-04-08 16:56 amp@java 閱讀(1842) 評(píng)論(2)  編輯  收藏 所屬分類: Java common

    評(píng)論

    # re: Java的位操作 2012-04-09 14:53 五月花
    二進(jìn)制就是二進(jìn)制,還要弄清是什么語(yǔ)言創(chuàng)建的?怎么創(chuàng)建的?  回復(fù)  更多評(píng)論
      

    #  內(nèi)容請(qǐng)不要發(fā)表任何與政治相關(guān)的內(nèi)容 2012-04-10 16:36 內(nèi)容請(qǐng)不要發(fā)表任何與政治相關(guān)的內(nèi)容
    內(nèi)容請(qǐng)不要發(fā)表任何與政治相關(guān)的內(nèi)容  回復(fù)  更多評(píng)論
      

    主站蜘蛛池模板: 中文字幕免费在线看线人动作大片| 亚洲精品免费在线视频| 亚洲国产精品丝袜在线观看| 国产无遮挡裸体免费视频| 成年女人看片免费视频播放器| 国产免费av片在线看| 最近免费中文字幕大全视频| 在线观看免费宅男视频| 永久免费看bbb| 午夜亚洲av永久无码精品| 亚洲国产精品13p| 亚洲综合伊人久久综合| 国产亚洲精品a在线无码| 亚洲国产精品嫩草影院在线观看 | 免费v片在线观看| 亚洲国产精品尤物YW在线观看| 亚洲综合区小说区激情区| 亚洲人成伊人成综合网久久久| 国产精品久久久亚洲| 91精品国产亚洲爽啪在线影院| 亚洲人成网男女大片在线播放| 久久亚洲精品国产亚洲老地址| 久久亚洲精品无码网站| 亚洲国产免费综合| 久久精品免费一区二区三区| 1000部啪啪未满十八勿入免费| 永久免费AV无码国产网站 | 国产免费一区二区三区不卡| 久久永久免费人妻精品| 91精品视频免费| 热99re久久精品精品免费| 亚洲综合色成在线播放| 久久亚洲AV成人无码国产 | 国产精品亚洲A∨天堂不卡| 亚洲精品偷拍无码不卡av| 亚洲精华国产精华精华液好用| 一级做a爰全过程免费视频毛片| 久久午夜无码免费| 成年女人免费碰碰视频| 亚洲熟妇无码另类久久久| 亚洲国产精品综合久久网各|