java基礎(chǔ)之自動裝箱

轉(zhuǎn)載:
http://www.cnblogs.com/dolphin0520/p/3780005.html
http://blog.csdn.net/chengzhezhijian/article/details/9628251

一.什么是裝箱泽西?什么是拆箱圾亏?

Java為每種基本數(shù)據(jù)類型都提供了對應(yīng)的包裝器類型。

在Java SE5之前斩狱,如果要生成一個數(shù)值為10的Integer對象柬姚,必須這樣進行:

Integer i = new Integer(10);

而在從Java SE5開始就提供了自動裝箱的特性,如果要生成一個數(shù)值為10的Integer對象,只需要這樣就可以了:

Integer i = 10;

這個過程中會自動根據(jù)數(shù)值創(chuàng)建對應(yīng)的 Integer對象,這就是裝箱艰匙。

那什么是拆箱呢?顧名思義霞揉,跟裝箱對應(yīng)旬薯,就是自動將包裝器類型轉(zhuǎn)換為基本數(shù)據(jù)類型:

Integer i = 10;  //裝箱
int n = i;   //拆箱

簡單一點說:

裝箱就是自動將基本數(shù)據(jù)類型轉(zhuǎn)換為包裝器類型;

拆箱就是自動將包裝器類型轉(zhuǎn)換為基本數(shù)據(jù)類型适秩。

下表是基本數(shù)據(jù)類型對應(yīng)的包裝器類型:

基本數(shù)據(jù) 包裝器類型
int(4字節(jié)) Integer
byte(1字節(jié)) Byte
short(2字節(jié)) Short
long(8字節(jié)) Long
float(4字節(jié)) Float
double(8字節(jié)) Double
char(2字節(jié)) Character
boolean(未定) Boolean

二.裝箱和拆箱是如何實現(xiàn)的绊序?

我們就以Interger類為例,下面看一段代碼:

public class Main {
    public static void main(String[] args) {
        Integer i = 10;
        int n = i;
    }
}

反編譯class文件之后得到如下內(nèi)容:

public class Main
{
  public static void main(String[] args)
  {
    Integer i = Integer.valueOf(10);
    int n = i.intValue();
  }
}

從反編譯得到的字節(jié)碼內(nèi)容可以看出秽荞,在裝箱的時候自動調(diào)用的是Integer的valueOf(int)方法骤公。而在拆箱的時候自動調(diào)用的是Integer的intValue方法。

其他的也類似扬跋,比如Double阶捆、Character。

因此可以用一句話總結(jié)裝箱和拆箱的實現(xiàn)過程:

裝箱過程是通過調(diào)用包裝器的valueOf方法實現(xiàn)的钦听,而拆箱過程是通過調(diào)用包裝器的 xxxValue方法實現(xiàn)的洒试。(xxx代表對應(yīng)的基本數(shù)據(jù)類型)。

三.面試中相關(guān)的問題

  1. 下面這段代碼的輸出結(jié)果是什么朴上?
public class Main {
    public static void main(String[] args) {

        Integer i1 = 100;
        Integer i2 = 100;
        Integer i3 = 200;
        Integer i4 = 200;

        System.out.println(i1==i2);
        System.out.println(i3==i4);
    }
}

也許有些朋友會說都會輸出false垒棋,或者也有朋友會說都會輸出true。但是事實上輸出結(jié)果是:

true
false

為什么會出現(xiàn)這樣的結(jié)果痪宰?

輸出結(jié)果表明i1和i2指向的是同一個對象叼架,而i3和i4指向的是不同的對象。

此時只需一看源碼便知究竟衣撬,下面這段代碼是Integer的valueOf方法的具體實現(xiàn):

/**
 * Returns an {@code Integer} instance representing the specified
 * {@code int} value.  If a new {@code Integer} instance is not
 * required, this method should generally be used in preference to
 * the constructor {@link #Integer(int)}, as this method is likely
 * to yield significantly better space and time performance by
 * caching frequently requested values.
 *
 * This method will always cache values in the range -128 to 127,
 * inclusive, and may cache other values outside of this range.
 *
 * @param  i an {@code int} value.
 * @return an {@code Integer} instance representing {@code i}.
 * @since  1.5
 */
public static Integer valueOf(int i) {
    if (i >= IntegerCache.low && i <= IntegerCache.high)
        return IntegerCache.cache[i + (-IntegerCache.low)];
    return new Integer(i);
}

而其中IntegerCache類的實現(xiàn)為:

/**
 * Cache to support the object identity semantics of autoboxing for values between
 * -128 and 127 (inclusive) as required by JLS.
 *
 * The cache is initialized on first usage.  The size of the cache
 * may be controlled by the {@code -XX:AutoBoxCacheMax=<size>} option.
 * During VM initialization, java.lang.Integer.IntegerCache.high property
 * may be set and saved in the private system properties in the
 * sun.misc.VM class.
 */

private static class IntegerCache {
    static final int low = -128;
    static final int high;
    static final Integer 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() {}
}

從這2段代碼可以看出乖订,在通過valueOf方法創(chuàng)建Integer對象的時候,如果數(shù)值在[-128,127]之間具练,便返回指向IntegerCache.cache中已經(jīng)存在的對象的引用乍构;否則創(chuàng)建一個新的Integer對象。

The Java Language Specification, 3rd Edition 寫道:

If the value p being boxed is true, false, a byte, a char in the range \u0000 to \u007f, or an int or short number between -128 and 127, then let r1 and r2 be the results of any two boxing conversions of p. It is always the case that r1 == r2.

為了節(jié)省內(nèi)存扛点,對于下列包裝對象的兩個實例哥遮,當它們的基本值相同時,他們總是==:

 Boolean:(全部緩存)
 Byte:(全部緩存)
 Character: (\u0000 - \u007f)(<= 127緩存)
 Short:(-128 — 127緩存)
 Long:(-128 — 127緩存)
 Float:(沒有緩存)

同樣對于垃圾回收器來說:

Integer i = 100;
i = null;//will not make any object available for GC at all.

這里的代碼不會有對象符合垃圾回收器的條件占键,這兒的i雖然被賦予null昔善,但它之前指向的是cache中的Integer對象,而cache沒有被賦null畔乙,所以Integer(100)這個對象還是存在君仆。

而如果i大于127或小于-128則它所指向的對象將符合垃圾回收的條件:

Integer i = 10000;
i = null;//will make the newly created Integer object available for GC.

使用Oracle/Sun JDK 6,在server模式下牲距,使用-XX:AutoBoxCacheMax=NNN參數(shù)即可將Integer的自動緩存區(qū)間設(shè)置為[-128,NNN]返咱。注意區(qū)間的下界固定在-128不可配置。

在client模式下該參數(shù)無效牍鞠。這個參數(shù)是server模式專有的咖摹,在c2_globals.hpp中聲明,默認值是128难述;不過這個默認值在默認條件下不起作用萤晴,要手動設(shè)置它的值或者是開啟-XX:+AggressiveOpts參數(shù)才起作用吐句。

在設(shè)置了-XX:+AggressiveOpts啟動參數(shù)后,AutoBoxCacheMax的默認值會被修改為20000并且生效店读。

參考arguments.cpp:

// Aggressive optimization flags  -XX:+AggressiveOpts
void Arguments::set_aggressive_opts_flags() {
#ifdef COMPILER2
  if (AggressiveOpts || !FLAG_IS_DEFAULT(AutoBoxCacheMax)) {
    if (FLAG_IS_DEFAULT(EliminateAutoBox)) {
      FLAG_SET_DEFAULT(EliminateAutoBox, true);
    }
    if (FLAG_IS_DEFAULT(AutoBoxCacheMax)) {
      FLAG_SET_DEFAULT(AutoBoxCacheMax, 20000);
    }

    // Feed the cache size setting into the JDK
    char buffer[1024];
    sprintf(buffer, "java.lang.Integer.IntegerCache.high=" INTX_FORMAT, AutoBoxCacheMax);
    add_property(buffer);
  }
  // ...
#endif
}

測試代碼:

// run with:
// java -server -XX:AutoBoxCacheMax=1000 TestAutoBoxCache

public class TestAutoBoxCache {
    public static void main(String[] args) {
        Integer a = 1000;
        Integer b = 1000;
        System.out.println(a == b);

        Integer c = 1001;
        Integer d = 1001;
        System.out.println(c == d);

        Integer e = 20000;
        Integer f = 20000;
        System.out.println(e == f);
    }
}

在命令行上測試:

$ javac TestAutoBoxCache.java

$ java TestAutoBoxCache
false
false
false

$ java -server TestAutoBoxCache
false
false
false

$ java -Djava.lang.Integer.IntegerCache.high=1000 TestAutoBoxCache
true
false
false

$ java -server -Djava.lang.Integer.IntegerCache.high=1000 TestAutoBoxCache
true
false
false

$ java -Djava.lang.Integer.IntegerCache.high=1001 TestAutoBoxCache
true
true
false

$ java -server -Djava.lang.Integer.IntegerCache.high=1001 TestAutoBoxCache
true
true
false

$ java -XX:AutoBoxCacheMax=1000 TestAutoBoxCache
Unrecognized VM option 'AutoBoxCacheMax=1000'
Could not create the Java virtual machine.

$ java -server -XX:AutoBoxCacheMax=1000 TestAutoBoxCache
true
false
false

$ java -server -XX:AutoBoxCacheMax=1001 TestAutoBoxCache
true
true
false

$ java -server -XX:+AggressiveOpts TestAutoBoxCache
true
true
true

中間報Unrecognized VM option 'AutoBoxCacheMax=1000'錯誤是因為這個參數(shù)只能在HotSpot Server VM上使用嗦枢,在HotSpot Client VM上不支持。

  1. 下面程序的輸出結(jié)果是什么屯断?
public class Main {
    public static void main(String[] args) {

        Integer a = 1;
        Integer b = 2;
        Integer c = 3;
        Integer d = 3;
        Integer e = 321;
        Integer f = 321;
        Long g = 3L;
        Long h = 2L;

        System.out.println(c==d);
        System.out.println(e==f);
        System.out.println(c==(a+b));
        System.out.println(c.equals(a+b));
        System.out.println(g==(a+b));
        System.out.println(g.equals(a+b));
        System.out.println(g.equals(a+h));
    }
}

運行結(jié)果:

true
false
true
true
true
false
true

這里面需要注意的是:當 “==”運算符的兩個操作數(shù)都是 包裝器類型的引用文虏,則是比較指向的是否是同一個對象,而如果其中有一個操作數(shù)是表達式(即包含算術(shù)運算)則比較的是數(shù)值(即會觸發(fā)自動拆箱的過程)殖演。

另外氧秘,對于包裝器類型,equals方法并不會進行類型轉(zhuǎn)換趴久。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末丸相,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子朋鞍,更是在濱河造成了極大的恐慌已添,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,968評論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件滥酥,死亡現(xiàn)場離奇詭異更舞,居然都是意外死亡,警方通過查閱死者的電腦和手機坎吻,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,601評論 2 382
  • 文/潘曉璐 我一進店門缆蝉,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人瘦真,你說我怎么就攤上這事刊头。” “怎么了诸尽?”我有些...
    開封第一講書人閱讀 153,220評論 0 344
  • 文/不壞的土叔 我叫張陵原杂,是天一觀的道長。 經(jīng)常有香客問我您机,道長穿肄,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,416評論 1 279
  • 正文 為了忘掉前任际看,我火速辦了婚禮咸产,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘仲闽。我一直安慰自己脑溢,他們只是感情好,可當我...
    茶點故事閱讀 64,425評論 5 374
  • 文/花漫 我一把揭開白布赖欣。 她就那樣靜靜地躺著屑彻,像睡著了一般验庙。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上酱酬,一...
    開封第一講書人閱讀 49,144評論 1 285
  • 那天壶谒,我揣著相機與錄音云矫,去河邊找鬼膳沽。 笑死,一個胖子當著我的面吹牛让禀,可吹牛的內(nèi)容都是我干的挑社。 我是一名探鬼主播,決...
    沈念sama閱讀 38,432評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼巡揍,長吁一口氣:“原來是場噩夢啊……” “哼痛阻!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起腮敌,我...
    開封第一講書人閱讀 37,088評論 0 261
  • 序言:老撾萬榮一對情侶失蹤阱当,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后糜工,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體弊添,經(jīng)...
    沈念sama閱讀 43,586評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,028評論 2 325
  • 正文 我和宋清朗相戀三年捌木,在試婚紗的時候發(fā)現(xiàn)自己被綠了油坝。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,137評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡刨裆,死狀恐怖澈圈,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情帆啃,我是刑警寧澤瞬女,帶...
    沈念sama閱讀 33,783評論 4 324
  • 正文 年R本政府宣布,位于F島的核電站努潘,受9級特大地震影響诽偷,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜慈俯,卻給世界環(huán)境...
    茶點故事閱讀 39,343評論 3 307
  • 文/蒙蒙 一渤刃、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧贴膘,春花似錦卖子、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,333評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽玄柠。三九已至,卻和暖如春诫舅,著一層夾襖步出監(jiān)牢的瞬間羽利,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,559評論 1 262
  • 我被黑心中介騙來泰國打工刊懈, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留这弧,地道東北人。 一個月前我還...
    沈念sama閱讀 45,595評論 2 355
  • 正文 我出身青樓虚汛,卻偏偏與公主長得像匾浪,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子卷哩,可洞房花燭夜當晚...
    茶點故事閱讀 42,901評論 2 345

推薦閱讀更多精彩內(nèi)容