国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 編程 > Java > 正文

詳解Java 自動裝箱與拆箱的實現原理

2019-11-26 12:30:53
字體:
來源:轉載
供稿:網友

什么是自動裝箱和拆箱

自動裝箱就是Java自動將原始類型值轉換成對應的對象,比如將int的變量轉換成Integer對象,這個過程叫做裝箱,反之將Integer對象轉換成int類型值,這個過程叫做拆箱。因為這里的裝箱和拆箱是自動進行的非人為轉換,所以就稱作為自動裝箱和拆箱。原始類型byte, short, char, int, long, float, double 和 boolean 對應的封裝類為Byte, Short, Character, Integer, Long, Float, Double, Boolean。

下面例子是自動裝箱和拆箱帶來的疑惑

 

  public class Test {     public static void main(String[] args) {         test();     }     public static void test() {       int i = 40;       int i0 = 40;       Integer i1 = 40;       Integer i2 = 40;       Integer i3 = 0;       Integer i4 = new Integer(40);       Integer i5 = new Integer(40);       Integer i6 = new Integer(0);       Double d1=1.0;       Double d2=1.0;       System.out.println("i=i0/t" + (i == i0));       System.out.println("i1=i2/t" + (i1 == i2));       System.out.println("i1=i2+i3/t" + (i1 == i2 + i3));       System.out.println("i4=i5/t" + (i4 == i5));       System.out.println("i4=i5+i6/t" + (i4 == i5 + i6));         System.out.println("d1=d2/t" + (d1==d2));        System.out.println();         }   }

請看下面的輸出結果跟你預期的一樣嗎?

輸出的結果:

i=i0    true
i1=i2   true
i1=i2+i3    true
i4=i5   false
i4=i5+i6    true
d1=d2 false

為什么會這樣?帶著疑問繼續往下看。

自動裝箱和拆箱的原理

自動裝箱時編譯器調用valueOf將原始類型值轉換成對象,同時自動拆箱時,編譯器通過調用類似intValue(),doubleValue()這類的方法將對象轉換成原始類型值。

明白自動裝箱和拆箱的原理后,我們帶著上面的疑問進行分析下Integer的自動裝箱的實現源碼。如下:

  public static Integer valueOf(int i) {    //判斷i是否在-128和127之間,如果不在此范圍,則從IntegerCache中獲取包裝類的實例。否則new一個新實例    if (i >= IntegerCache.low && i <= IntegerCache.high)      return IntegerCache.cache[i + (-IntegerCache.low)];    return new Integer(i);  }  //使用亨元模式,來減少對象的創建(亨元設計模式大家有必要了解一下,我認為是最簡單的設計模式,也許大家經常在項目中使用,不知道他的名字而已)  private static class IntegerCache {    static final int low = -128;    static final int high;    static final Integer cache[];    //靜態方法,類加載的時候進行初始化cache[],靜態變量存放在常量池中    static {      // high value may be configured by property      int h = 127;      String integerCacheHighPropValue =        sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high");      if (integerCacheHighPropValue != null) {        try {          int i = parseInt(integerCacheHighPropValue);          i = Math.max(i, 127);          // Maximum array size is Integer.MAX_VALUE          h = Math.min(i, Integer.MAX_VALUE - (-low) -1);        } catch( NumberFormatException nfe) {          // If the property cannot be parsed into an int, ignore it.        }      }      high = h;      cache = new Integer[(high - low) + 1];      int j = low;      for(int k = 0; k < cache.length; k++)        cache[k] = new Integer(j++);      // range [-128, 127] must be interned (JLS7 5.1.7)      assert IntegerCache.high >= 127;    }    private IntegerCache() {}  }

Integer i1 = 40; 自動裝箱,相當于調用了Integer.valueOf(40);方法。

首先判斷i值是否在-128和127之間,如果在-128和127之間則直接從IntegerCache.cache緩存中獲取指定數字的包裝類;不存在則new出一個新的包裝類。

IntegerCache內部實現了一個Integer的靜態常量數組,在類加載的時候,執行static靜態塊進行初始化-128到127之間的Integer對象,存放到cache數組中。cache屬于常量,存放在java的方法區中。

接著看下面是java8種基本類型的自動裝箱代碼實現。如下:

  //boolean原生類型自動裝箱成Boolean  public static Boolean valueOf(boolean b) {    return (b ? TRUE : FALSE);  }  //byte原生類型自動裝箱成Byte  public static Byte valueOf(byte b) {    final int offset = 128;    return ByteCache.cache[(int)b + offset];  }  //byte原生類型自動裝箱成Byte  public static Short valueOf(short s) {    final int offset = 128;    int sAsInt = s;    if (sAsInt >= -128 && sAsInt <= 127) { // must cache      return ShortCache.cache[sAsInt + offset];    }    return new Short(s);  }  //char原生類型自動裝箱成Character  public static Character valueOf(char c) {    if (c <= 127) { // must cache      return CharacterCache.cache[(int)c];    }    return new Character(c);  }  //int原生類型自動裝箱成Integer  public static Integer valueOf(int i) {    if (i >= IntegerCache.low && i <= IntegerCache.high)      return IntegerCache.cache[i + (-IntegerCache.low)];    return new Integer(i);  }  //int原生類型自動裝箱成Long  public static Long valueOf(long l) {    final int offset = 128;    if (l >= -128 && l <= 127) { // will cache      return LongCache.cache[(int)l + offset];    }    return new Long(l);  }  //double原生類型自動裝箱成Double  public static Double valueOf(double d) {    return new Double(d);  }  //float原生類型自動裝箱成Float  public static Float valueOf(float f) {    return new Float(f);  }

通過分析源碼發現,只有double和float的自動裝箱代碼沒有使用緩存,每次都是new 新的對象,其它的6種基本類型都使用了緩存策略。

使用緩存策略是因為,緩存的這些對象都是經常使用到的(如字符、-128至127之間的數字),防止每次自動裝箱都創建一此對象的實例。

而double、float是浮點型的,沒有特別的熱的(經常使用到的)數據的,緩存效果沒有其它幾種類型使用效率高。

下面在看下裝箱和拆箱問題解惑。

  //1、這個沒解釋的就是true  System.out.println("i=i0/t" + (i == i0)); //true  //2、int值只要在-128和127之間的自動裝箱對象都從緩存中獲取的,所以為true  System.out.println("i1=i2/t" + (i1 == i2)); //true  //3、涉及到數字的計算,就必須先拆箱成int再做加法運算,所以不管他們的值是否在-128和127之間,只要數字一樣就為true  System.out.println("i1=i2+i3/t" + (i1 == i2 + i3));//true   //比較的是對象內存地址,所以為false  System.out.println("i4=i5/t" + (i4 == i5)); //false  //5、同第3條解釋,拆箱做加法運算,對比的是數字,所以為true  System.out.println("i4=i5+i6/t" + (i4 == i5 + i6));//true     //double的裝箱操作沒有使用緩存,每次都是new Double,所以false  System.out.println("d1=d2/t" + (d1==d2));//false

相信你看到這就應該能明白上面的程序輸出的結果為什么是true,false了,只要掌握原理,類似的問題就迎刃而解了,希望對大家的學習有所幫助,也希望大家多多支持武林網。

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 黑河市| 陆丰市| 视频| 宁河县| 澄迈县| 利辛县| 安远县| 镇安县| 赤城县| 高淳县| 鱼台县| 刚察县| 泗洪县| 温泉县| 安康市| 桐乡市| 城步| 萨嘎县| 黄骅市| 桑日县| 蒙阴县| 玉龙| 沂南县| 紫阳县| 楚雄市| 瓦房店市| 钦州市| 台中市| 苏尼特右旗| 景宁| 重庆市| 当雄县| 无锡市| 千阳县| 罗平县| 淮南市| 全椒县| 济阳县| 贡嘎县| 镇康县| 平果县|