欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

詳解Java 自動(dòng)裝箱與拆箱的實(shí)現(xiàn)原理

 更新時(shí)間:2017年04月22日 16:01:36   作者:jijs  
本篇文章主要介紹了詳解Java 自動(dòng)裝箱與拆箱的實(shí)現(xiàn)原理,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧

什么是自動(dòng)裝箱和拆箱

自動(dòng)裝箱就是Java自動(dòng)將原始類型值轉(zhuǎn)換成對應(yīng)的對象,比如將int的變量轉(zhuǎn)換成Integer對象,這個(gè)過程叫做裝箱,反之將Integer對象轉(zhuǎn)換成int類型值,這個(gè)過程叫做拆箱。因?yàn)檫@里的裝箱和拆箱是自動(dòng)進(jìn)行的非人為轉(zhuǎn)換,所以就稱作為自動(dòng)裝箱和拆箱。原始類型byte, short, char, int, long, float, double 和 boolean 對應(yīng)的封裝類為Byte, Short, Character, Integer, Long, Float, Double, Boolean。

下面例子是自動(dòng)裝箱和拆箱帶來的疑惑

 

  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();     
    } 
  }

請看下面的輸出結(jié)果跟你預(yù)期的一樣嗎?

輸出的結(jié)果:

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

為什么會(huì)這樣?帶著疑問繼續(xù)往下看。

自動(dòng)裝箱和拆箱的原理

自動(dòng)裝箱時(shí)編譯器調(diào)用valueOf將原始類型值轉(zhuǎn)換成對象,同時(shí)自動(dòng)拆箱時(shí),編譯器通過調(diào)用類似intValue(),doubleValue()這類的方法將對象轉(zhuǎn)換成原始類型值。

明白自動(dòng)裝箱和拆箱的原理后,我們帶著上面的疑問進(jìn)行分析下Integer的自動(dòng)裝箱的實(shí)現(xiàn)源碼。如下:

  public static Integer valueOf(int i) {
    //判斷i是否在-128和127之間,如果不在此范圍,則從IntegerCache中獲取包裝類的實(shí)例。否則new一個(gè)新實(shí)例
    if (i >= IntegerCache.low && i <= IntegerCache.high)
      return IntegerCache.cache[i + (-IntegerCache.low)];
    return new Integer(i);
  }


  //使用亨元模式,來減少對象的創(chuàng)建(亨元設(shè)計(jì)模式大家有必要了解一下,我認(rèn)為是最簡單的設(shè)計(jì)模式,也許大家經(jīng)常在項(xiàng)目中使用,不知道他的名字而已)
  private static class IntegerCache {
    static final int low = -128;
    static final int high;
    static final Integer cache[];

    //靜態(tài)方法,類加載的時(shí)候進(jìn)行初始化cache[],靜態(tài)變量存放在常量池中
    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; 自動(dòng)裝箱,相當(dāng)于調(diào)用了Integer.valueOf(40);方法。

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

IntegerCache內(nèi)部實(shí)現(xiàn)了一個(gè)Integer的靜態(tài)常量數(shù)組,在類加載的時(shí)候,執(zhí)行static靜態(tài)塊進(jìn)行初始化-128到127之間的Integer對象,存放到cache數(shù)組中。cache屬于常量,存放在java的方法區(qū)中。

接著看下面是java8種基本類型的自動(dòng)裝箱代碼實(shí)現(xiàn)。如下:

  //boolean原生類型自動(dòng)裝箱成Boolean
  public static Boolean valueOf(boolean b) {
    return (b ? TRUE : FALSE);
  }

  //byte原生類型自動(dòng)裝箱成Byte
  public static Byte valueOf(byte b) {
    final int offset = 128;
    return ByteCache.cache[(int)b + offset];
  }

  //byte原生類型自動(dòng)裝箱成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原生類型自動(dòng)裝箱成Character
  public static Character valueOf(char c) {
    if (c <= 127) { // must cache
      return CharacterCache.cache[(int)c];
    }
    return new Character(c);
  }

  //int原生類型自動(dòng)裝箱成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原生類型自動(dòng)裝箱成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原生類型自動(dòng)裝箱成Double
  public static Double valueOf(double d) {
    return new Double(d);
  }

  //float原生類型自動(dòng)裝箱成Float
  public static Float valueOf(float f) {
    return new Float(f);
  }

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

使用緩存策略是因?yàn)?,緩存的這些對象都是經(jīng)常使用到的(如字符、-128至127之間的數(shù)字),防止每次自動(dòng)裝箱都創(chuàng)建一此對象的實(shí)例。

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

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

  //1、這個(gè)沒解釋的就是true
  System.out.println("i=i0\t" + (i == i0)); //true
  //2、int值只要在-128和127之間的自動(dòng)裝箱對象都從緩存中獲取的,所以為true
  System.out.println("i1=i2\t" + (i1 == i2)); //true
  //3、涉及到數(shù)字的計(jì)算,就必須先拆箱成int再做加法運(yùn)算,所以不管他們的值是否在-128和127之間,只要數(shù)字一樣就為true
  System.out.println("i1=i2+i3\t" + (i1 == i2 + i3));//true 
  //比較的是對象內(nèi)存地址,所以為false
  System.out.println("i4=i5\t" + (i4 == i5)); //false
  //5、同第3條解釋,拆箱做加法運(yùn)算,對比的是數(shù)字,所以為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

相信你看到這就應(yīng)該能明白上面的程序輸出的結(jié)果為什么是true,false了,只要掌握原理,類似的問題就迎刃而解了,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

  • Java運(yùn)算符從見過到掌握下

    Java運(yùn)算符從見過到掌握下

    計(jì)算機(jī)的最基本用途之一就是執(zhí)行數(shù)學(xué)運(yùn)算,作為一門計(jì)算機(jī)語言,Java也提供了一套豐富的運(yùn)算符來操縱變量,本篇對大家的學(xué)習(xí)或工作具有一定的價(jià)值,緊接上篇,需要的朋友可以參考下
    2021-09-09
  • Spring?Security權(quán)限注解啟動(dòng)及邏輯處理使用示例

    Spring?Security權(quán)限注解啟動(dòng)及邏輯處理使用示例

    這篇文章主要為大家介紹了Spring?Security權(quán)限注解啟動(dòng)及邏輯處理使用示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-07-07
  • 使用Spring Data JDBC實(shí)現(xiàn)DDD聚合的示例代碼

    使用Spring Data JDBC實(shí)現(xiàn)DDD聚合的示例代碼

    這篇文章主要介紹了使用Spring Data JDBC實(shí)現(xiàn)DDD聚合的示例代碼,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2018-09-09
  • 基于Java Callable接口實(shí)現(xiàn)線程代碼實(shí)例

    基于Java Callable接口實(shí)現(xiàn)線程代碼實(shí)例

    這篇文章主要介紹了基于Java Callable接口實(shí)現(xiàn)線程代碼實(shí)例,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-08-08
  • Java工廠模式的使用細(xì)則介紹

    Java工廠模式的使用細(xì)則介紹

    工廠模式,是一種實(shí)例化對象的方式,只要輸入需要實(shí)例化對象的名字,就可以通過工廠對象的相應(yīng)工廠函數(shù)來制造你需要的對象
    2023-02-02
  • Mybatis實(shí)現(xiàn)動(dòng)態(tài)建表代碼實(shí)例

    Mybatis實(shí)現(xiàn)動(dòng)態(tài)建表代碼實(shí)例

    這篇文章主要介紹了Mybatis實(shí)現(xiàn)動(dòng)態(tài)建表代碼實(shí)例,解釋一下,就是指根據(jù)傳入的表名,動(dòng)態(tài)地創(chuàng)建數(shù)據(jù)庫表,以供后面的業(yè)務(wù)場景使用,
    而使用 Mybatis 的動(dòng)態(tài) SQL,就能很好地為我們解決這個(gè)問題,需要的朋友可以參考下
    2023-10-10
  • Java類型轉(zhuǎn)換valueOf與parseInt區(qū)別探討解析

    Java類型轉(zhuǎn)換valueOf與parseInt區(qū)別探討解析

    這篇文章主要為大家介紹了Java類型轉(zhuǎn)換valueOf與parseInt區(qū)別探討解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-09-09
  • springboot+mybatis如何屏蔽掉mybatis日志

    springboot+mybatis如何屏蔽掉mybatis日志

    這篇文章主要介紹了springboot+mybatis如何屏蔽掉mybatis日志問題,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-05-05
  • Spring Boot Web應(yīng)用程序配置詳解

    Spring Boot Web應(yīng)用程序配置詳解

    這篇文章主要介紹了Spring Boot Web應(yīng)用程序配置詳解,本文中將介紹一些Web應(yīng)用程序最常用的配置,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2018-05-05
  • Java跨域問題分析與解決方法詳解

    Java跨域問題分析與解決方法詳解

    這篇文章主要介紹了Java跨域問題分析與解決方法,跨域問題是在Web應(yīng)用程序中,由于同源策略的限制,導(dǎo)致瀏覽器無法發(fā)送跨域請求,也無法獲取跨域響應(yīng)的問題,感興趣想要詳細(xì)了解可以參考下文
    2023-05-05

最新評論