我的漫漫程序之旅

          專注于JavaWeb開發(fā)
          隨筆 - 39, 文章 - 310, 評(píng)論 - 411, 引用 - 0
          數(shù)據(jù)加載中……

          盡情享受每一個(gè)Byte

          下面的程序循環(huán)遍歷byte數(shù)值,以查找某個(gè)特定值。這個(gè)程序會(huì)打印出什么呢?
          public class BigDelight {
              
          public static void main(String[] args) 
          {
                  
          for (byte b = Byte.MIN_VALUE; b < Byte.MAX_VALUE; b++
          {
                       
          if (b == 0x90
          )
                           System.out.print(
          "Joy!"
          );
                  }

              }

          }

          這個(gè)循環(huán)在除了Byte.MAX_VALUE之外所有的byte數(shù)值中進(jìn)行迭代,以查找0x90。這個(gè)數(shù)值適合用byte表示,并且不等于Byte.MAX_VALUE,因此你可能會(huì)想這個(gè)循環(huán)在該迭代會(huì)找到它一次,并將打印出Joy!。但是,所見為虛。如果你運(yùn)行該程序,就會(huì)發(fā)現(xiàn)它沒有打印任何東西。怎么回事?

          簡(jiǎn)單地說(shuō),0x90是一個(gè)int常量,它超出了byte數(shù)值的范圍。這與直覺是相悖的,因?yàn)?x90是一個(gè)兩位的十六進(jìn)制字面常量,每一個(gè)十六進(jìn)制位都占據(jù)4個(gè)比特的位置,所以整個(gè)數(shù)值也只占據(jù)8個(gè)比特,即1個(gè)byte。問題在于byte是有符號(hào)類型。常量0x90是一個(gè)正的最高位被置位的8位int數(shù)值。合法的byte數(shù)值是從-128到+127,但是int常量0x90等于+144。

          拿一個(gè)byte與一個(gè)int進(jìn)行的比較是一個(gè)混合類型比較(mixed-type comparison)。如果你把byte數(shù)值想象為蘋果,把int數(shù)值想象成為桔子,那么該程序就是在拿蘋果與桔子比較。請(qǐng)考慮表達(dá)式((byte)0x90 == 0x90),盡管外表看起來(lái)是成立的,但是它卻等于false。

          為了比較byte數(shù)值(byte)0x90和int數(shù)值0x90,Java通過(guò)拓寬原始類型轉(zhuǎn)換將byte提升為一個(gè)int[JLS 5.1.2],然后比較這兩個(gè)int數(shù)值。因?yàn)閎yte是一個(gè)有符號(hào)類型,所以這個(gè)轉(zhuǎn)換執(zhí)行的是符號(hào)擴(kuò)展,將負(fù)的byte數(shù)值提升為了在數(shù)字上相等的int數(shù)值。在本例中,該轉(zhuǎn)換將(byte)0x90提升為int數(shù)值-112,它不等于int數(shù)值0x90,即+144。

          由于系統(tǒng)總是強(qiáng)制地將一個(gè)操作數(shù)提升到與另一個(gè)操作數(shù)相匹配的類型,所以混合類型比較總是容易把人搞糊涂。這種轉(zhuǎn)換是不可視的,而且可能不會(huì)產(chǎn)生你所期望的結(jié)果。有若干種方法可以避免混合類型比較。我們繼續(xù)有關(guān)水果的比喻,你可以選擇拿蘋果與蘋果比較,或者是拿桔子與桔子比較。你可以將int轉(zhuǎn)型為byte,之后你就可以拿一個(gè)byte與另一個(gè)byte進(jìn)行比較了:

          if (b == (byte)0x90)
              System.out.println(
          "Joy!"
          );
          或者,你可以用一個(gè)屏蔽碼來(lái)消除符號(hào)擴(kuò)展的影響,從而將byte轉(zhuǎn)型為int,之后你就可以拿一個(gè)int與另一個(gè)int進(jìn)行比較了:
          if ((b & 0xff== 0x90)
              System.out.print(
          "Joy!"
          );
          上面的兩個(gè)解決方案都可以正常運(yùn)行,但是避免這類問題的最佳方法還是將常量值移出到循環(huán)的外面,并將其在一個(gè)常量聲明中定義它。下面是我們對(duì)此作出的第一個(gè)嘗試:
          public class BigDelight {
              
          private static final byte TARGET = 0x90
          ;   
              
          public static void main(String[] args) 
          {
                  
          for (byte b = Byte.MIN_VALUE; b <
           
                       Byte.MAX_VALUE; b
          ++
          {
                       
          if (b ==
           TARGET)
                           System.out.print(
          "Joy!"
          );
                  }

              }

          }

          遺憾的是,它根本就通不過(guò)編譯。常量聲明有問題,編譯器會(huì)告訴你問題所在:0x90對(duì)于byte類型來(lái)說(shuō)不是一個(gè)有效的數(shù)值。如果你想下面這樣訂正該聲明,那么程序?qū)⑦\(yùn)行得非常好:
          private static final byte TARGET = (byte)0x90;
          總之,要避免混合類型比較,因?yàn)樗鼈儍?nèi)在地容易引起混亂.為了幫助實(shí)現(xiàn)這個(gè)目標(biāo),請(qǐng)使用聲明的常量替代“魔幻數(shù)字”。你已經(jīng)了解了這確實(shí)是一個(gè)好主意:它說(shuō)明了常量的含義,集中了常量的定義,并且根除了重復(fù)的定義。現(xiàn)在你知道它還可以強(qiáng)制你去為每一個(gè)常量賦予適合其用途的類型,從而消除了產(chǎn)生混合類型比較的一種根源。

          對(duì)語(yǔ)言設(shè)計(jì)的教訓(xùn)是byte數(shù)值的符號(hào)擴(kuò)展是產(chǎn)生bug和混亂的一種常見根源。而用來(lái)抵銷符號(hào)擴(kuò)展效果所需的屏蔽機(jī)制會(huì)使得程序顯得混亂無(wú)序,從而降低了程序的可讀性。因此,byte類型應(yīng)該是無(wú)符號(hào)的。還可以考慮為所有的原始類型提供定義字面常量的機(jī)制,這可以減少對(duì)易于產(chǎn)生錯(cuò)誤的類型轉(zhuǎn)換的需求



          posted on 2008-01-12 17:26 々上善若水々 閱讀(729) 評(píng)論(0)  編輯  收藏 所屬分類: J2SE

          主站蜘蛛池模板: 长治县| 安阳市| 鄂伦春自治旗| 邹平县| 明溪县| 抚顺市| 密云县| 丰都县| 泸溪县| 长治县| 永嘉县| 靖江市| 炎陵县| 唐河县| 拉孜县| 彰化县| 武邑县| 肥西县| 鞍山市| 尉犁县| 襄樊市| 通河县| 穆棱市| 武威市| 温州市| 军事| 衡阳县| 柳河县| 安岳县| 晋州市| 南城县| 广汉市| 澳门| 铁岭市| 西宁市| 朝阳县| 滨州市| 新丰县| 麦盖提县| 涟源市| 文登市|