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

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

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

    上善若水
    In general the OO style is to use a lot of little objects with a lot of little methods that give us a lot of plug points for overriding and variation. To do is to be -Nietzsche, To bei is to do -Kant, Do be do be do -Sinatra
    posts - 146,comments - 147,trackbacks - 0

    J2SE5.0后推出了自動裝箱和拆箱的功能,以提高我們的開發效率,然而自動裝箱和拆箱實際上是通過編譯器來支持的(并非語言本身,或者說虛擬機),因而這種支持也隱藏了部分內部實質,再加上某些類的優化(比如Integer里面的緩存等,參看關于緩存節),就更加容易在特定的環境下產生問題,并且如果不知道原來還無法調試。以下先是簡單的介紹了編譯器對裝箱和拆箱的實現,并根據實現簡單介紹一下可能會遇到的幾個問題。

    裝箱和拆箱實現

    以下裝箱和拆箱代碼:

           Object value = 10;
           
    int intValue = (Integer)value;
           Integer newIntValue 
    = new Integer(10);

     

    編譯成字節碼如下:

         0 bipush 10

         2 invokestatic java.lang.Integer.valueOf(int) : java.lang.Integer [20]

         5 astore_1 [value]

         6 aload_1 [value]

         7 checkcast java.lang.Integer [21]

        10 invokevirtual java.lang.Integer.intValue() : int [26]

        13 istore_2 [intValue]

        14 new java.lang.Integer [21]

        17 dup

        18 bipush 10

        20 invokespecial java.lang.Integer(int) [30]

        23 astore_3 [newIntValue]

    從以上字節碼可以看到10首先調用valueOf方法轉換為Integer實例,再賦值該value,而value強制轉換成Integer類后,會調用intValue方法,后賦值給intValue。這就是用編譯器來實現裝箱和拆箱。

     

    奇怪的NullPointerException

    查看以下代碼:

           Integer value = null;
           
    int intValue = value;

     

    可以編譯通過,但是運行的時候卻會發生NullPointerException。這是由什么引起的呢?依然看一下字節碼就可以了:

         0 aconst_null

         1 astore_1 [value]

         2 aload_1 [value]

        3 invokevirtual java.lang.Integer.intValue() : int [20]

         6 istore_2 [intValue]

    從字節碼中可以看到,從value賦值該intValue事實上是直接在value實例上調用intValue函數。

    對當前代碼,我們可以一眼就看出當前valuenull的問題,但是如果這個null是在很遠以外的地方賦值的呢?或者是間接賦值呢?這個時候遇到這種問題就會比較詭異了。

     

    相等與不相等問題

    查看一下代碼:

           Integer value1 = 100;
           Integer value2 
    = 100;
           System.out.println(
    "value1 == value2 is " + (value1 == value2));
          
           Integer value3 
    = 200;
           Integer value4 
    = 200;
           System.out.println(
    "value3 == value4 is " + (value3 == value4));

     

    這段代碼會是什么結果?

    value1 == value2 is true

    value3 == value4 is false

     

    兩段代碼就是值不一樣,其他的都一樣,竟然會有區別?這個奧妙就因為裝箱過程中調用的是valueOf方法,而valueOf方法對值在-128127之間的數值緩存了(參見關于緩存一節),因而value1value2的引用是相同的,而value3value4的引用是不一樣的,而==比較的是引用,因而才會出現以上的結果。

    這確的做法應該是:

           Integer value1 = 100;
           Integer value2 
    = 100;
           System.out.println(
    "value1 == value2 is " + (value1.equals(value2)));
          
           Integer value3 
    = 200;
           Integer value4 
    = 200;

           System.out.println("value3 == value4 is " + (value3.equals(value4))); 

    這樣的結果就是預料的結果了:

    value1 == value2 is true

    value3 == value4 is true

     

    所以我們要慎用“==”操作符。

     

    String中的相等與不等

    String中也有類似的情況,查看一下代碼:

           String str1 = "abc";
           String str2 
    = "abc";
           System.out.println(
    "str1 == str2 is " + (str1 == str2));
          
           String str3 
    = new String("abc");
           String str4 
    = new String("abc");
           System.out.println(
    "str3 == str4 is " + (str3 == str4));

     

    執行結果:

    str1 == str2 is true

    str3 == str4 is false

     

    這是因為str1str2使用的是同一個字符串,即在字符常量中的字符串,而str3str4在使用字符常量中的字符為參數又創建出了兩個新的字符串對象,因而在引用比較情況下是不等的。我們可以從字節碼中得到這些信息(刪除打印的代碼):

         0 ldc <String "abc"> [20]

         2 astore_1 [str1]

         3 ldc <String "abc"> [20]

         5 astore_2 [str2]

         6 new java.lang.String [22]

         9 dup

        10 ldc <String "abc"> [20]

        12 invokespecial java.lang.String(java.lang.String) [24]

        15 astore_3 [str3]

        16 new java.lang.String [22]

        19 dup

        20 ldc <String "abc"> [20]

        22 invokespecial java.lang.String(java.lang.String) [24]

        25 astore 4 [str4]

    正確的做法還是調用equals方法,而不是使用“==”操作符。

     

    關于緩存

    據目前信息,有緩存的類有:ByteShortIntegerLong以及Boolean類。而這種緩存也只是在調用valueOf(靜態)方法的時候才會存在(裝箱正是調用了valueOf方法)。對整型,緩存的值都是-128127(包括-128127)之間,其他值都不緩存,而對Boolean類型只有truefalse值。代碼如下:

    public final class Integer extends Number {
        
    public static Integer valueOf(int i) {
            
    if(i >= -128 && i <= IntegerCache.high)
                
    return IntegerCache.cache[i + 128];
            
    else
            
    return new Integer(i);
    }
    public final class Boolean {
        
    public static Boolean valueOf(boolean b) {
            
    return (b ? TRUE : FALSE);
        }


    2011-01-05

     

     

    posted on 2011-07-20 23:09 DLevin 閱讀(5783) 評論(2)  編輯  收藏 所屬分類: Core Java

    FeedBack:
    # re: Java中的裝箱與拆箱
    2011-07-25 22:29 | AlleNny
    so many years ~  回復  更多評論
      
    # re: Java中的裝箱與拆箱
    2011-07-26 01:12 | DLevin
    It really is, but it is not so old for a new guy like me, especially for the cache strategy applied by the compiler. :)@AlleNny
      回復  更多評論
      
    主站蜘蛛池模板: 亚洲免费观看在线视频| 免费成人福利视频| 国产成人精品久久亚洲高清不卡| 亚洲熟妇无码乱子AV电影| 日韩视频免费一区二区三区| 国产精品入口麻豆免费观看| 华人在线精品免费观看| 夜夜爽妓女8888视频免费观看| 亚洲av产在线精品亚洲第一站| 亚洲av综合色区| 亚洲综合网站色欲色欲| 亚洲性久久久影院| 亚洲av无码成人精品区在线播放| 久久这里只有精品国产免费10| 真实国产乱子伦精品免费| 免费网站看av片| 人妻在线日韩免费视频| 久久国产免费直播| 一级毛片成人免费看a| 亚洲GV天堂无码男同在线观看| 亚洲av产在线精品亚洲第一站| 亚洲欧洲精品一区二区三区| 亚洲av无码国产精品色午夜字幕 | 国产亚洲精品精品国产亚洲综合| 在线观看免费精品国产| 午夜a级成人免费毛片| 久久不见久久见免费影院| 黄色成人免费网站| 2021国产精品成人免费视频| 日本高清在线免费| 国产成人免费在线| 亚洲精品免费在线| 久久国内免费视频| 在线观看无码的免费网站| 成人五级毛片免费播放| 国产无遮挡吃胸膜奶免费看| 国产极品粉嫩泬免费观看| xvideos亚洲永久网址| 亚洲综合区小说区激情区| 又黄又爽的视频免费看| 亚洲伊人成无码综合网 |