關于Integer ,作為int 包裝類,新手經常會犯的錯誤是,比較兩個Integer 用 ==,作為有經驗的開發我們知道,包裝類、String 都應用用equals方法進行判斷。
在實際項目中,我們經常會有枚舉值定義成Integer類型,有相當部分同學不注意,使用== 進行了比較,但是似乎又也沒怎麼出現Bug。這就不得不提起 Integer内部類 IntegerCache,它緩存了[-128,127] 的對象,這裡使用了享元模式,避免了對象的重複創建。
因為枚舉值數量通常比較小,在[-128,127] 之間,代碼中也沒有誰變态到 new Integer(value),所以,許多場景使用的是 IntegerCache 緩存的對象,所以== 沒出現了問題。但不能說這麼用沒有錯,程序員要嚴謹,以防後續用到數值超過緩存的範圍,且不排除誰用new Integer 創建對象。
雖然IntegerCache 不對外暴露,但是Java反射,可是神通廣大,如果用反射把一些緩存的值改掉,就會産生“有意思的”結果。下面代碼大家覺得輸出什麼
Integer one = Integer.valueOf(1); Class iClass = Integer.class; Field valueField = iClass.getDeclaredField(value valueField.setAccessible(true); valueField.set(one,128); System.out.println((Integer)1 == 128);
輸出true
其實這個涉及知識點不少,涉及Java 自動拆箱、Integer緩存
左邊包裝類 右邊基本類型,會把左邊拆卸為基本類型,由于它的value 已經被改為128了,所以輸出true .
但是上述代碼稍微修改下, 改為 Integer(1) == (Integer)128
Integer one = Integer.valueOf(1); Class iClass = Integer.class; Field valueField = iClass.getDeclaredField(value valueField.setAccessible(true); valueField.set(one,128); System.out.println((Integer)1 == (Integer)128);
結果就為false。
因為上面代碼兩個Integer 類型,比較是不是同一個對象,顯然128不在緩存中,
如果把128 改為緩存範圍内一個數呢,如下,結果也會為false。
public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException { Integer one = Integer.valueOf(1); Class iClass = Integer.class; Field valueField = iClass.getDeclaredField(value valueField.setAccessible(true); valueField.set(one,3); System.out.println((Integer)1 == (Integer)3); }
學C 的,估計第一次接觸這個要吐血了,既然說了順便複習下Integer 類型值默認null ,int 默認值0。這個IntgerCache 确實饒了點。
同樣的Long 也有類似的Cache,值得一提的是redis 中有類似的緩存,隻是範圍不一樣,編程複雜度與空間開銷方面,如果是我會選擇簡單,期待jdk某個版本會把它幹掉。
講完,後面持續輸出
,
更多精彩资讯请关注tft每日頭條,我们将持续为您更新最新资讯!