天天看點

integer比較_面試難點突破!Integer對象的緩存政策一個簡單的面試題從自動裝箱談Integer緩存再談==和equals()總結

integer比較_面試難點突破!Integer對象的緩存政策一個簡單的面試題從自動裝箱談Integer緩存再談==和equals()總結

一個簡單的面試題

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); }
           

運作結果:

truefalse
           

你答對了嗎?

integer比較_面試難點突破!Integer對象的緩存政策一個簡單的面試題從自動裝箱談Integer緩存再談==和equals()總結

從自動裝箱談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=} 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() {} }
           

緩存類在第一次使用Integer類時被初始化。通過一個for循環初始化了一個擁有256個Integer對象的數組供開發人員使用。它們的範圍預設是[-128 , 127],127可以通過修改JVM啟動參數-XX:AutoBoxCacheMax=size進行調整。這種方式通過使用相同的對象引用來實作緩存和複用,以此來節省記憶體和提高性能。

再談==和equals()

雙等于==比較的是對象的記憶體位址,對于-128到127之間的整數,隻要這個引用是通過自動裝箱或者顯式valueOf()指向一個Integer對象,那麼它一定會指向一個IntegerCache.cache數組中的對象,是以實體位址一定相等,而在這個區間以外的整數,因為沒有緩存的原因,需要通過new Integer()的方式開辟一塊新的實體位址來存儲這個對象,是以實體位址一定不同。是以才會有前面面試題中的結果。

Integer.equals()方法,提供了比較兩個Integer對象的方法,是以不管是通過new 還是 valueOf方式建立的Integer對象,在實際的業務需求中,往往都是需要比較對象中存儲的整數值而不是實體位址,是以,為了避免混淆,應當都使用equals方式來比較兩個Integer對象,這樣可以減少很多問題。

總結

代碼應當是服務于業務的,而不是面試題。這種==比較兩個Integer對象的方式應該僅僅在面試題中出現,而不應該是在業務實作中出現,雖然某些時候,可以實作一樣的效果,但是代碼應該不僅能夠實作邏輯的正确性,也應該能夠表達一種正确的語義,使他人在閱讀你的代碼時能夠清楚的明白這行代碼所要表達的含義。

但并不是說我們不需要了解它的實作過程和需要注意的問題,這道面試題雖然可能不會真正的運用到實際的業務實作中去,但是卻提供了一種幫助我們深入了解jdk的手段,使我們更好的了解到API開發人員在幫助我們解決什麼問題。是以,不論是工作還是學習,都應該認清我們的需要。

綜上,就是對Integer對象緩存政策的剖析和感想,如有疑問,歡迎文末留言。

---歡迎關注【Java聖鬥士】,我是你們的小可愛(✪ω✪) Morty---

---專注IT職場經驗、IT技術分享的靈魂寫手---

---每天帶你領略IT的魅力---

---期待與您陪伴!---