Intger和int做比較的坑

Integer 緩存(IntegerCache)是 Java 5 中引入的一個有助於節省內存、提高性能的特性

廢話不多說,看一個栗子

/**
 * @author :Vimonster
 * @time : 2019/12/19 10:41
 * @slogan: 任時間再怎樣低頭呢喃,也要不揮淚後風雨兼程
 * @description:
 *
 * 關於Integer 和 int 的一些注意事項
 *
 */
public class IntegerBug {


    public static void main(String[] args) {

        test1();
        test2();
    }

    /**
     * 比較值問題
     *
     */
    private static void test1(){

        Integer a = 110;
        int b = 110;
        Integer c = new Integer(110);

        System.out.println(a == b); //true 此處相等 應爲Integer在和int比較時會自動拆箱 變爲int 此處a自動拆箱爲int類型 對象的比較也就變成了值的比較
        System.out.println(a == c); //false 因爲c使用了new對象 c的值其實在堆空間 而 a 的值在常量池 兩個都是對象 對象地址不一樣 所以是false
    }


    /**
     *
     * -128與127之間,Integer會自動存在IntegerCache.cache 直接從內存中去取,不在這個範圍則會new新對象
     *
     */
    private static void test2(){
        int a = 127;
        int b = 127;
        Integer c = 127;            //編譯的時候 翻譯爲:Integer c = Integer.valueOf(127);
        Integer d = new Integer(127);
        Integer e = 127;
        System.out.println(a == b); //true
        System.out.println(a == c); //true
        System.out.println(c == d); //false
        System.out.println(a == d); //true
        System.out.println(c == e); //true  c 和 e 實際上是同一個對象。所以使用”==“比較返回true。
        test3();
    }

    private static void test3(){
        int a = 128;
        int b = 128;
        Integer c = 128;
        Integer d = new Integer(128);
        Integer e = 128;
        System.out.println(a == b); //true
        System.out.println(a == c); //true
        System.out.println(c == d); //false
        System.out.println(a == d); //true
        //todo 注意 java6之後如果不修改 XX:AutoBoxCacheMax=size 此處是false
        // 如果修改 XX:AutoBoxCacheMax=size 使其size大於128此處就爲true
        // !!!java6之後 IntegerCache.high 可以修改  !!!java6之後 IntegerCache.high 可以修改 !!!java6之後 IntegerCache.high 可以修改
        System.out.println(c == e); //false //128超出了Integer緩存範圍 c 和 e 都是new 出來的對象
    }

}

java6之後在不通過JVM啓動參數修改IntegerCache值的範圍的前提下,處於節省內存的考慮,JVM會緩存-128到127的Integer對象 即:IntegerCache.low=-128 IntegerCache.high=127,也就是在IntegerCache=[-128, 127]

  • 自動裝箱:

將一個int賦值給一個Integer,會發生自動裝箱,裝箱過程系統對int類型的值X執行了Integer.valueOf(X);

Integer a = 10;

//在編譯時 上述代碼被翻譯爲下面的代碼

//10在[-128, 127]範圍內所以直接從緩存池返回10對應的Intger對象,否則將會new一個新的Integer賦值給a

Integer a = Integer.valueof(10); 

  • 自動拆箱:

一個Integer對象和一個int值作比較,會發生自動拆箱,拆箱過程系統對Integer類型的對象X執行了X.intValue();

Integer a = 110;
int b = 110;
//在Integer對象a 和 基本類型 b 做比較時 a 會做這樣的轉化 a = a.intValue(); 變成一個int類型的值 
// 再和b做比較 此時變成了數值之間的比較
System.out.println(a == b);


回頭再看test1方法

Integer a = 110;

這一行簡單的代碼,其實發生了很多事。 110是基本類型 賦值 給一個Intger類型的對象 a  ,其實在編譯過程中,由於自動裝箱, 這行代碼會翻譯成 如下:

Integer c = Integer.valueOf(110);

我們看一下jdk1.8的Integer.valueOf(x)的源碼

/**
*
* 將基本類型int 處理完後 返回Integer對象的過程叫做自動裝箱
*/
public static Integer valueOf(int i) {
        //判斷int類型的值i 是否介於Integer緩存池的最大值和最小值之間
        if (i >= IntegerCache.low && i <= IntegerCache.high)
            //如果i在Integer緩存池的範圍 直接從緩存池拿裝箱後的對象
            return IntegerCache.cache[i + (-IntegerCache.low)];
        //如果i不在緩存池範圍內 new一個新的對象返回
        return new Integer(i);
    }

知道了上述源碼後,再來看test3方法中的 c == e 爲什麼返回是false了


Integer c = 128; // c不在[-128, 127]範圍內 根據上述源碼得知裝箱過程中 c = new Integer(128);
Integer e = 128; // e不在[-128, 127]範圍內 根據上述源碼得知裝箱過程中 e = new Integer(128);
//c是一個new 出來的對象 e是也是一個new出來的對象 在堆內存中對應的是兩個對象 所以此處爲false
System.out.println(c == e); //false
  • 如何修改IntegerCache的範圍

都說Integer緩存池的大小在-128和127之間,也就是IntegerCache.low=-128  IntegerCache.high=127  

嚴格來說應該是如果自己不指定緩存值的範圍, 默認的是這樣, 什麼緩存池的範圍還可以自己指定???

是的, 你沒聽錯,在java6之後, 可以使用JVM的啓動參數設置最大值 (通過JVM的啓動參數

-XX:AutoBoxCacheMax=size 進行修改)

不信我用idea來演示一下,idea修改JVM啓動參數

1.idea右上角如圖中所示 點擊一下有個下拉框 點擊Edit Configurations..選項 彈出框如圖二所示

2.在該頁面的VM options選項中填寫-XX:AutoBoxCacheMax=256 設置Integer緩存值最大值爲256

此時再次運行上面的test3 你會發現 c == e 會變成true 因爲此處的128在新設置的Integer緩存池-128~256範圍之內,所以在進行裝箱操作的時候,是直接從Integer緩存池中拿的對象, c和e都是從緩存池中拿的同一個對象, 所以c == e 是true

private static void test3(){
        int a = 128;
        int b = 128;
        Integer c = 128;
        Integer d = new Integer(128);
        Integer e = 128;
        System.out.println(a == b); //true
        System.out.println(a == c); //true
        System.out.println(c == d); //false
        System.out.println(a == d); //true
        //todo 注意 java6之後如果不修改 XX:AutoBoxCacheMax=size 此處是false
        // 如果修改 XX:AutoBoxCacheMax=size 使其size大於128此處就爲true
        // !!!java6之後 IntegerCache.high 可以修改  !!!java6之後 IntegerCache.high 可以修改 !!!java6之後 IntegerCache.high 可以修改
        System.out.println(c == e); //true//128未超出了Integer新設置的最大緩存256 c 和 e 是同一個對象 是直接從緩存池中拿到的對象
    }

所以從嚴格意義上來說 在java6之後, 在不通過JVM啓動參數修改Integer緩存池的範圍值時, 系統的Integer緩存池的大小纔是在-128和127之間。

 

上述就是Integer和int之間作比較常見的一些問題嘍 !!!

 

如果覺得生活很迷茫,就只管埋頭變強、

                                                                                                                                                      2019-12-19   --於南京

發佈了61 篇原創文章 · 獲贊 19 · 訪問量 7萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章