有趣的Java之包裝類型的緩存與"==" equals

在進入正文之前 , 我們寫來看一段代碼

public static void main(String[] args) {
        Integer i1 = 127;
        Integer i2 = 127;
        Integer i3 = new Integer(127);
        System.out.println("one==:" + i1 == i2);
        System.out.println("one2==:" + i1 == i3);
        System.out.println("twoeq:"+i1.equals(i3));
        System.out.println("threq:"+i1.equals(i2));
        i1 = 128;
        i2 = 128;
        System.out.println("four==:" + i1 == i2);
        System.out.println("fiveq:" + i1.equals(i2));
    }

分析這段代碼 , 按照我們原來的想法 , 由於在比較對象爲基本數據類型時 , “==”比較的是值是否相等 , 但是 Integer 是 int 的包裝類 , 它是一個對象 , 所以 “==” 在這裏和 equals 一樣比較的是對象的引用是否相同 .
粗略一看 , 好像他們的輸出應該全爲 false , 因爲它們都創建了新的對象 .
的確 , 如果是其他對象的話 , 我們的猜想是沒有錯的 , 但是包裝類型不一樣 .
equals 在 包裝類型和 String 類中被重寫了 , 比較的是值是否相等
Object equals 方法實現如下:

public boolean eqauls(Object obj){
    return (this == obj);
}

在包裝類型中重寫 :

public boolean equals(Object obj) {
        if (obj instanceof Integer) {
            return value == ((Integer)obj).intValue();
        }
        return false;
    }

可以看到 , java 將 Object 幫我們轉換成了 Integer(對應包裝類) , 然後通過 Integer.intValue() 與 value(其值)使用 “==” 進行比較 , 結果自然而然是 true

接下來我們看看equals 在 String 中的重寫

 public boolean equals(Object anObject) {
        //如果引用相等
        if (this == anObject) {
            return true;
        }
        if (anObject instanceof String) {
            String anotherString = (String) anObject;
            int n = value.length;
            if (n == anotherString.value.length) {
                char v1[] = value;
                char v2[] = anotherString.value;
                int i = 0;
                //將 value 和 與之相比的 value 值拆分爲 char 一一比較
                while (n-- != 0) {
                    if (v1[i] != v2[i])
                            return false;
                    i++;
                }
                return true;
            }
        }
        return false;
    }

因此我們對最開始的那段程序有了新的結論 , 他的輸出應該是

one==:false
one2==:false
twoeq:true
threq:true
four==:false
fiveq:true

如果這個時候你心滿意足 , 那恭喜你得不到正確答案了

包裝類型除了重寫了 equals , 在後臺還爲我們做了一件事情 – 緩存 !
java 爲了節省內存,設計了基本數據類型包裝類的緩存,就是程序啓動時,初始化的數值依次放在緩存池中,當你直接給 Integer 對象賦值時,它每次首先去緩存去查,如果有的話,直接將新 new 出的對象引用指向緩存池中的對象 ;
當然緩存池也不是無限大的 , Integer 緩存的範圍是[-128,127],超出範圍就需要重新在堆內存中new了,Byte 和 boolean 將全部緩存
所以我們運行最開始的程序的時候會發現 , 當 i1 , i2 爲 128 時 , 輸出的是 false
終於真相大白了 , 所以它最後的輸出應該是 :

one==:true //緩存
one2==:false // i3 爲新建對象 new Integer(127);
twoeq:true
threq:true  
four==:false //超出緩存
fiveq:true

PS : java 雖然沒有對 String 做緩存 , 但是可以用 String.intern() 實現同樣效果

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