首頁 >Java >java教程 >Java自動裝箱、自動拆箱與Integer快取怎麼使用

Java自動裝箱、自動拆箱與Integer快取怎麼使用

WBOY
WBOY轉載
2023-04-24 22:28:121631瀏覽

1. 前言

自動裝箱和自動拆箱是什麼? Integer快取是什麼?它們之間有什麼關係?

先來看一道題目。

Integer a = new Integer(1);
Integer b = new Integer(1);
System.out.println(a==b);
Integer c = 1;
Integer d = 1;
System.out.println(c==d);
Integer e = 128;
Integer f = 128;
System.out.println(e==f);

先答,後看答案。

答案是false true false,你答對了嗎?

既然一塊出現了,就一起串算知識點

2. 包裝類別

Java中基本資料型別有八種,可以分成三類:

  • 字元類型:char

  • 布林型:boolean

  • 數值類型:byte short int long float double

包裝類別是將八種基本資料型別包裝為了類,使它們可以使用Java的三大特性:封裝、繼承、多型態。對應關係如下:

基本資料型別 對應的包裝類別
byte Byte
short #Short
int Integer
long Long
#float Float
double Double
boolean Boolean
char Character

數值型對應的六個包裝類別都繼承於Number類別。

3. 自動裝箱與自動拆箱

八種基本資料型別對應八種包裝類,那麼它們是怎麼進行資料轉換的?

//基本数据类型转包装类
//1.有参构造
Integer a = new Integer(1);
//2.实际上,有参构造的参数也可以是字符串,不过要使用正确的数据,“123abc”不可能会转换为Integer类型
Integer b = new Integer("123");
//3.valueOf()
Integer c = Integer.valueOf(123);
//包装类转基本数据类型(xxxValue()  float是floatValue() double是doubleValue())
int d = a.intValue();

以上的形式都是比較符合認知的,取得一個物件可以透過new或呼叫某個方法,取得一個值就呼叫物件的某個屬性。

Java 5.0之後可以不用這麼麻煩了,增加了自動裝箱和自動拆箱的新特性,實際上兩個概念非常好理解。

int a = 10;
Integer b = a;  //自动装箱
int c = b;  //自动拆箱

乍一看,物件=數值的這種形式並不符合認知,但是藉助於自動裝箱和自動拆箱就可以實現。實際上,編譯器還是藉助於valueOf()和xxxValue()實現的。

我們來看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)
        return IntegerCache.cache[i + (-IntegerCache.low)];
    return new Integer(i);
}

valueOf()並不是簡單地返回Integer對象,而是先進行了一次判斷,輸入的數據符合某個範圍的話,將會返回一個特定的對象,從註釋上來看,這個範圍預設是[-128,127],而且可能是更大的範圍;而超過這個範圍就會回傳new的物件。而使用到的IntegerCache資料就是Integer的快取了。

4. Interger快取

數值計算日常使用比較頻繁,那麼如果不停的去new Integer物件的話,開銷會非常大,所以,Java在執行程式時會自動產生一個靜態數組作為緩存,Integer預設對應的緩存數組範圍在[-128,127],只要資料在這個範圍內,就可以從快取中拿到對應的物件。

看一下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=<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() {}
}

可以看到,IntegerCache是​​Integer的靜態內部類,valueOf()調用的IntegerCache.cache就是數組對象,數組的大小取決於範圍內的最大值和最小值,預設為[- 128,127],當然,(註釋上說)也可以透過JVM修改這個範圍(這我不了解)。然後數組內的元素都會被賦一個Integer對象,快取也就形成了。

存在數組緩存,也意味著,如果取值在[-128,127],使用valueOf()或自動裝箱創建的Integer物件都是在數組中取出,因此物件指向的記憶體位址是完全一樣的。而如果用new或是超出這個範圍都要重新建立物件。

當然,不只Integer有快取機制,Byte、Short、Long、Character都具有快取機制。其中Byte,Short,Integer,Long的範圍為 -128 到 127,Character的範圍為 0 到 127。

5. 回答題目

Integer a = new Integer(1);
Integer b = new Integer(1);
System.out.println(a==b);
Integer c = 1;
Integer d = 1;
System.out.println(c==d);
Integer e = 128;
Integer f = 128;
System.out.println(e==f);

1.new創建的兩個對象,即使值相同,指向的內存地址也是不同的,使用==進行比較返回結果為false

2.自動裝箱和快取機制,兩個對像其實是相同的,回傳結果為true

3.超出快取範圍,執行時會new新對象,兩個對像不同,回傳結果為false

以上是Java自動裝箱、自動拆箱與Integer快取怎麼使用的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文轉載於:yisu.com。如有侵權,請聯絡admin@php.cn刪除