todayx.org
          todayx.org
          posts - 39,comments - 60,trackbacks - 0
          歷史上的今天
          回顧歷史的今天,歷史就像生活的一面鏡子;可以了解歷史的這一天發(fā)生的事件;借古可以鑒今;歷史是不能忘記的.要記住歷史的每一天
          http://www.todayx.org/

          等于還是不等于?

          看來(lái)看下面的一段代碼:

           

             代碼片段1

          Java代碼  收藏代碼
          1. public static void main(final String[] args) {  
          2.     Integer a = new Integer(100);  
          3.     Integer b = 100;  
          4.     System.out.println(a == b);   
          5. }  

           

           這段代碼的輸出是什么?相信很多人都會(huì)很容易的猜到:false,因?yàn)閍、b兩個(gè)對(duì)象的地址不同,用“==”比較時(shí)是false。恭喜你,答對(duì)了。

           

          再看下面的一段代碼:

            

             代碼片段2

          Java代碼  收藏代碼
          1. public static void main(final String[] args) {  
          2.     Integer a = 100;  
          3.     Integer b = 100;  
          4.     System.out.println(a == b);   
          5. }  

           

          你可能會(huì)回答,這沒(méi)什么不一樣啊,所以還是false。很遺憾,如果你執(zhí)行上面的一段代碼,結(jié)果是true。

           

          上面的代碼可能讓你有些意外,那好吧,再看看下面的這段代碼:

           

              代碼片段3

          Java代碼  收藏代碼
          1. public static void main(final String[] args) {  
          2.     Integer a = 156;  
          3.     Integer b = 156;  
          4.     System.out.println(a == b);   
          5. }  

           結(jié)果是true嗎?很遺憾,如果你執(zhí)行上面的一段代碼,結(jié)果是false。

           

           感到吃驚嗎?那最后再看下面的一段代碼:

           

              代碼片段4

          Java代碼  收藏代碼
          1. public static void main(final String[] args) {  
          2.     Integer a = Integer.valueOf(100);  
          3.     Integer b = 100;  
          4.     System.out.println(a == b);   
          5. }  

          最后的結(jié)果,可能你已經(jīng)猜到了,是true。

          為什么會(huì)這樣?

          現(xiàn)在我們分析一下上面的代碼。可以很容易的看出,這一系列代碼的最終目的都是用“==”對(duì)兩個(gè)對(duì)象進(jìn)行比較。Java中,如果用“==”比較兩個(gè)對(duì)象結(jié)果為true,說(shuō)明這兩個(gè)對(duì)象實(shí)際上是同一個(gè)對(duì)象,false說(shuō)明是兩個(gè)對(duì)象。

           

          現(xiàn)在,我們來(lái)看看為什么會(huì)出現(xiàn)上面的現(xiàn)象。

           

          我們先看代碼片段4:最后的運(yùn)行結(jié)果是true,說(shuō)明a、b兩個(gè)對(duì)象實(shí)際上是同一個(gè)對(duì)象。但是a對(duì)象是通過(guò)調(diào)用Integer的valueOf方法創(chuàng)建的,而b對(duì)象是通過(guò)自動(dòng)裝箱創(chuàng)建出來(lái)的,怎么會(huì)是同一個(gè)對(duì)象呢?難道問(wèn)題在字節(jié)碼那里,畢竟Java程序是依靠虛擬器運(yùn)行字節(jié)碼來(lái)實(shí)現(xiàn)的。

           

          通過(guò)jdk中自帶的工具javap,解析字節(jié)碼,核心的部分摘取如下:

          Java代碼  收藏代碼
          1. 0:  bipush  100  
          2. 2:  invokestatic    #16; //Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;  
          3. 5:  astore_1  
          4. 6:  bipush  100  
          5. 8:  invokestatic    #16; //Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;  

          代碼中我們只調(diào)用了一次Integer.valueOf方法,但是字節(jié)碼中出現(xiàn)了兩次對(duì)Integer.valueOf方法的調(diào)用。那么另一次是哪里呢?只可能在自動(dòng)裝箱時(shí)調(diào)用的。因此這段代碼實(shí)際上等價(jià)于:

          Java代碼  收藏代碼
          1. public static void main(final String[] args) {  
          2.     Integer a = Integer.valueOf(100);  
          3.     Integer b = Integer.valueOf(100);  
          4.     System.out.println(a == b);   
          5. }  

           現(xiàn)在問(wèn)題就簡(jiǎn)單了:看jdk源代碼,查看valueOf方法的具體實(shí)現(xiàn):

          Java代碼  收藏代碼
          1. public static Integer valueOf(int i) {  
          2.     final int offset = 128;  
          3.     if (i >= -128 && i <= 127) { // must cache   
          4.         return IntegerCache.cache[i + offset];  
          5.     }  
          6.     return new Integer(i);  
          7. }  

           

          看到這兒,上面的代碼就很明確了:對(duì)于-128到127的數(shù)字,valueOf返回的是緩存中的對(duì)象。所以兩次調(diào)用Integer.valueOf(100)返回的都是同一個(gè)對(duì)象。

          我們?cè)傧瓤创a片段3:根據(jù)上面的分析,代碼片段3實(shí)際上等價(jià)于以下代碼:

          Java代碼  收藏代碼
          1. public static void main(final String[] args) {  
          2.     Integer a = Integer.valueOf(156);  
          3.     Integer b = Integer.valueOf(156);  
          4.     System.out.println(a == b);   
          5. }  

           由于156不在-128到127范圍內(nèi),所以兩個(gè)對(duì)象都是通過(guò)new Integer()的方式創(chuàng)建的,所以最后結(jié)果為false。

           

           片段1和片段2就不做具體分析了,相信讀者可以自行分析。

           

           最后,請(qǐng)大家思考一下問(wèn)題:通過(guò)上面的分析,了解到整數(shù)的自動(dòng)裝箱是通過(guò)Integer.valueOf(int number)實(shí)現(xiàn)的,那么自動(dòng)拆箱是如何實(shí)現(xiàn)的呢?


          歷史上的今天
          回顧歷史的今天,歷史就像生活的一面鏡子;可以了解歷史的這一天發(fā)生的事件;借古可以鑒今;歷史是不能忘記的.要記住歷史的每一天
          http://www.todayx.org/
          posted on 2012-02-01 00:21 todayx.org 閱讀(1976) 評(píng)論(3)  編輯  收藏

          FeedBack:
          # re: Java迷題:等于,還是不等于?
          2012-02-01 13:57 | 楊Coder
          呵呵!不分析底層,還真不知道有這么一回事!作者很有探究精神。  回復(fù)  更多評(píng)論
            
          # re: Java迷題:等于,還是不等于?
          2012-02-05 14:21 | allenny
          1,2,4很好理解,3倒是第一次注意到,Integer只有8位嗎?  回復(fù)  更多評(píng)論
            
          # re: Java迷題:等于,還是不等于?
          2012-03-30 18:29 | 網(wǎng)友
          看起來(lái)眼熟呢?
          http://xiaoyu1985ban.iteye.com/blog/1384191
          有點(diǎn)不地道哦。  回復(fù)  更多評(píng)論
            

          只有注冊(cè)用戶登錄后才能發(fā)表評(píng)論。


          網(wǎng)站導(dǎo)航:
           
          主站蜘蛛池模板: 琼海市| 汕尾市| 晋江市| 云林县| 沙湾县| 丹江口市| 澄江县| 香河县| 福清市| 洛隆县| 买车| 建湖县| 大田县| 通化县| 福清市| 永丰县| 都昌县| 和顺县| 巴彦淖尔市| 大新县| 建水县| 铜山县| 寻甸| 宝丰县| 太谷县| 茂名市| 石景山区| 安阳县| 伊宁市| 上栗县| 渭南市| 商南县| 陈巴尔虎旗| 元江| 铁力市| 吉安市| 博爱县| 玉山县| 平顶山市| 吉首市| 宜都市|