Java的自動拆裝箱與Integer的緩存機制

 

轉載請註明原文地址:http://www.javashuo.com/article/p-qkunbogr-ee.htmlhtml

 

一:基本類型與包裝類型

    咱們知道,Java有8大基本數據類型,4整2浮1符1布。java

    咱們在實際開發中,除了使用到數據的值以外,還會涉及到對數據的操做。根據「面向對象」編程的思想,這些常見的操做被抽象成方法,封裝到了一個類中,一個基本數據類型對應一個這樣的類,這些類統稱爲「包裝類」。編程

 

    8大基本類型 分別對應 8個包裝類,再加上兩個用於高精度運算的包裝類,共有10大包裝類。分別爲:數組

    Byte:對應 byte 類型緩存

    Short:對應 short類型jvm

    Integer:對應 int類型ide

    Long:對應 long類型函數

    Float:對應 float類型工具

    Double:對應 double類型性能

    Character:對應 char類型

    Boolean:對應 boolean類型

    BigInteger:支持任意精度[長度]的整數運算。

    BigDecmail:支持任意精度的浮點數運算,主要用於金額計算。

    

    包裝類的好處:它提供了一系列操做本類型數據的方法,能夠爲咱們在開發過程當中操做8大基本類型數據提供充足的「工具」。

 

二:自動拆裝箱

    一、裝箱

    把基本數據類型轉換成包裝類的過程就是打包裝,英文名boxing,翻譯爲裝箱。

    二、拆箱

    反之,把包裝類轉換成基本數據類型的過程就是拆包裝,英文對應於unboxing,中文翻譯爲拆箱。

    三、自動拆裝箱

    自動裝箱: 就是將基本數據類型自動轉換成對應的包裝類。
    自動拆箱:就是將包裝類自動轉換成對應的基本數據類型。

    四、自動拆裝箱的發生場景

    1)自動拆裝箱的過程主要發生在賦值操做上:將一個基本數據類型的值符給包裝類變量,則進行自動裝箱操做;將一個包裝類變量的值賦給基本數據類型變量,則發生自動拆箱操做。

    2)將基本數據類型放入集合類時:Java中的集合類只能接收對象類型,當咱們把基本數據類型放入集合類中的時候,會進行自動裝箱成對應的包裝類對象後再放入。

    3)基本數據變量與包裝類變量進行運算操做時:基本數據變量與包裝類變量進行比較運算、數學運算、三目運算時,會自動拆箱成基本類型再進行運算。

    4)函數返回值自動拆裝箱:當函數定義時,指定了函數返回值是包裝類,則return 一個基本數據類型值時,就會自動裝箱;若是定義的函數返回值是基本數據類型時,return一個包裝類對象會自動拆箱。

 

三:自動拆裝箱帶來的問題

    一、包裝對象的數值比較,不能簡單的使用==,雖然-128到127之間的數字能夠[下文中解釋],可是這個範圍以外仍是須要使用equals比較。【== 比較的是地址,equals比較的是值】

    二、因爲自動拆箱,若是包裝類對象爲null,那麼自動拆箱時就有可能拋出NPE[null pointer exception]。

    三、若是在一個for循環中有大量拆裝箱操做,會浪費不少資源。

   

  

四:Integer的緩存機制—— -128到127之間的數字自動裝箱後的會返回同一個對象。

    詳情可參閱:Java中整型的緩存機制 這篇文章。

    首先看個例子:

package com.javapapers.java;public class JavaIntegerCache {
    public static void main(String... strings) {

        Integer integer1 = 3; //整數3自動裝箱
        Integer integer2 = 3; //整數3自動裝箱

        if (integer1 == integer2) //兩個自動裝箱後對象比較
            System.out.println("integer1 == integer2");
        else
            System.out.println("integer1 != integer2");

        Integer integer3 = 300;//整數300自動裝箱
        Integer integer4 = 300;//整數300自動裝箱

        if (integer3 == integer4)//兩個自動裝箱後對象比較
            System.out.println("integer3 == integer4");
        else
            System.out.println("integer3 != integer4");

    }}

    上面的代碼輸出的結果是:

integer1 == integer2
integer3 != integer4

    也就是說:整數3自動裝箱後賦值給a、b兩個引用變量,這兩個引用指向的是同一個對象。

                   可是整數300自動裝箱後賦值給c、d兩個引用變量,這兩個引用指向的是不一樣對象。

    那麼問題來了——都是自動裝箱,爲何不一樣數值自動裝箱的結果不同呢?——這是因爲Integer的緩存機制致使的。

 

   一、爲何要實現Integer的緩存機制呢?

    在實際開發過程當中,會常常在不經意間就觸發了自動拆裝箱機制。咱們知道,自動裝箱會建立一個包裝類對象,一套程序跑下來,會生成多少個這樣的對象?那開銷得多大啊。

    所以,出於節省內存和提升性能的目的,從Java5開始,爲咱們提供了Integer的緩存機制。

 

  二、Integer的緩存機制的生效邏輯

   這個緩存機制是怎麼工做的呢?咱們來看一下Integer類的取值方法——valueOf的源碼。

/**
     * 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) //先判斷整數值爲是否處於IntegerCache.low~IntegerCache.high之間的緩存值
            return IntegerCache.cache[i + (-IntegerCache.low)]; //是的話,則從緩存數組中取對應的包裝類對象之間返回
        return new Integer(i);//否,則建立一個新的包裝類對象返回
    }

    從代碼中能夠看出,自動裝箱時,建立對象以前先從IntegerCache.cache中尋找,若是沒找到才使用new新建對象。

 

    IntegerCache 類源碼

/**
     * 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=} 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; //默承認緩存的最小值是 -128
        static final int high; //可緩存的最大值
        static final Integer cache[]; //緩存數組

        static {
            // high value may be configured by property 可緩存最大值可經過jvm參數指定
            int h = 127; //默承認緩存最大值爲127
            String integerCacheHighPropValue =
                sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high"); //從JVM參數中獲取可緩存最大值配置
            if (integerCacheHighPropValue != null) {
                try {
                    int i = parseInt(integerCacheHighPropValue);
                    i = Math.max(i, 127);//將配置值與127之間取較大值,即:可緩存值最小爲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;//斷言:可緩存最大值必須大於等於127
        }

        private IntegerCache() {}
    }

    從上面能夠得知,Integer緩存數組中保存了 -128~h(h>=127) 的值的包裝類對象,其中h值能夠經過JVM參數 -XX:AutoBoxCacheMax=size 修改【這也是JVM調優的一個經常使用配置項】。

    至於最小範圍 -128~127 之間,是由於這個範圍的數字是最被普遍使用的。

    IntegerCache是Integer類中定義的一個private static的內部類,所以在程序中,第一次使用Integer對象的時候會須要必定的額外時間來初始化這個緩存。

 

   三、其餘包裝類的緩存機制

     ByteCache用於緩存Byte對象:固定範圍: -128 到 127,不能更改。

     ShortCache用於緩存Short對象:固定範圍: -128 到 127,不能更改。

     LongCache用於緩存Long對象:固定範圍: -128 到 127,不能更改。

     CharacterCache用於緩存Character對象:固定範圍: 0 到 127,不能更改。

     舉個例子:

若是一個變量p的值是:

-128至127之間的整數

true 和 false的布爾值

‘\u0000’至 ‘\u007f’之間的字符

之間時,將p自動裝箱成a和b兩個對象,能夠直接使用a==b判斷a和b的值是否相等。
相關文章
相關標籤/搜索