Java基础————理解Integer对象的缓存策略
一個簡單的面試題
public static void main(String[] args) {Integer in1 = 100;Integer in2 = 100;Integer in3 = 200;Integer in4 = 200;System.out.println(in1 == in2);System.out.println(in3 == in4);}運行結果:
true false從自動裝箱談Integer緩存
上述面試題中,in1,in2,in3,in4四個Integer對象都是通過直接賦值int變量完成初始化的,這種賦值方式我們成為自動裝箱。
實際上,自動裝箱功能只是Java編譯器自動幫我們完成了調用Integer.valueOf(int i)的過程,也就是說:
Integer in1 = 100;<-等價于->Integer in1 = Integer.valueOf(100);了解了這個道理,我們再來回想上面這個問題:為什么一樣的調用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);}我們看到,在jdk1.5中,加入了valueOf的這個實現過程。在if條件中,如果 i 的值在[IntegerCache.low , IntegerCache.high]之間的話,則取IntegerCache.cache中的一個元素。
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 propertyint 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_VALUEh = 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() {}}緩存類在第一次使用Integer類時被初始化。通過一個for循環初始化了一個擁有256個Integer對象的數組供開發人員使用。它們的范圍默認是[-128 , 127],127可以通過修改JVM啟動參數-XX:AutoBoxCacheMax=size進行調整。這種方式通過使用相同的對象引用來實現緩存和復用,以此來節省內存和提高性能。
在通過valueOf創建新的Integer對象之前會先在IntegerCache.cache中查找,如果有我們需要的值則直接返回一個指向此對象的引用。否則,才會通過new Integer()方式直接創建Integer對象。
再談==和equals()
雙等于==比較的是對象的內存地址,對于-128到127之間的整數,只要這個引用是通過自動裝箱或者顯式valueOf()指向一個Integer對象,那么它一定會指向一個IntegerCache.cache數組中的對象,因此物理地址一定相等,而在這個區間以外的整數,因為沒有緩存的原因,需要通過new Integer()的方式開辟一塊新的物理地址來存儲這個對象,因此物理地址一定不同。所以才會有前面面試題中的結果。
Integer.equals()方法,提供了比較兩個Integer對象的方法,所以不管是通過new 還是 valueOf方式創建的Integer對象,在實際的業務需求中,往往都是需要比較對象中存儲的整數值而不是物理地址,所以,為了避免混淆,應當都使用equals方式來比較兩個Integer對象,這樣可以減少很多問題。
總結
代碼應當是服務于業務的,而不是面試題。這種==比較兩個Integer對象的方式應該僅僅在面試題中出現,而不應該是在業務實現中出現,雖然某些時候,可以實現一樣的效果,但是代碼應該不僅能夠實現邏輯的正確性,也應該能夠表達一種正確的語義,使他人在閱讀你的代碼時能夠清楚的明白這行代碼所要表達的含義。
但并不是說我們不需要理解它的實現過程和需要注意的問題,這道面試題雖然可能不會真正的運用到實際的業務實現中去,但是卻提供了一種幫助我們深入了解jdk的手段,使我們更好的了解到API開發人員在幫助我們解決什么問題。所以,不論是工作還是學習,都應該認清我們的需要。
綜上,就是對Integer對象緩存策略的剖析和感想,如有疑問,歡迎文末留言。
總結
以上是生活随笔為你收集整理的Java基础————理解Integer对象的缓存策略的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: HTMLCSS————CSS常用选择器及
- 下一篇: Java中HashMap的常用操作