Java整數緩存Integer.valueOf(127)==Integer.valueOf(127)為True

在一次採訪中,我的一個朋友被問到,如果我們有兩個整數對象,Integer a = 127; Integer b = 127;為什麼要a == b的值為true ?在本文中,我將嘗試回答這個問題,並解釋這個問題的答案。這個問題的簡短回答是,將int文字直接分配給Integer引用是自動裝箱概念的一個示例,其中文字值到對象轉換代碼由編譯器處理,因此在編譯期間編譯器轉換Integer a = 127;為Integer a = Integer.valueOf(127);。

所述Integer類維護內部IntegerCache為整數,其通過從默認範圍-128 to 127和Integer.valueOf()方法返回的上述範圍的對象從該高速緩存中。所以a == b返回因為真正的a和b兩者都指向同一個對象。

為了理解簡短的回答讓我們首先了解Java類型,Java中的所有類型都分為兩類

  1. 基元類型: Java中有8種基本類型(byte,short,int,long,float,double,char和boolean),它們以二進制位的形式直接保存它們的值。
  2. 例如,int a = 5; int b = 5;在這裡a和b直接持有的5二進制值,如果我們試圖比較a和b使用a == b我們實際上是在比較5 == 5其返回true。
  3. 引用類型:除基本類型之外的所有類型都位於引用類型的類別下,例如類,接口,枚舉,數組等。引用類型保存對象的地址而不是對象本身。
  4. 例如Integer a = new Integer(5); Integer b = new Integer(5),這裡a和b不成立的二進制值5,而不是a和b擁有兩個不同的對象其中兩個對象包含的值的內存地址5。因此,如果我們嘗試比較a和b使用,a == b,我們實際上是比較這兩個單獨的內存地址,因此我們得到false,執行實際的相等a,b我們需要執行a.euqals(b)。
  • 參考類型進一步分為4類Strong, Soft, Weak and Phantom。

我們知道Java為所有原始類型提供包裝類,並支持自動裝箱和自動拆箱。

// Example of auto-boxing, here c is a reference type
Integer c = 128; // Compiler converts this line to Integer c = Integer.valueOf(128);
// Example of auto-unboxing, here e is a primitive type
int e = c; // Compiler converts this line to int e = c.intValue();

現在,如果我們創建兩個整數對象a並b,嘗試使用相等運算符進行比較==,我們將得到,false因為兩個引用都持有不同的對象

Integer a = 128; // Compiler converts this line to Integer a = Integer.valueOf(128);
Integer b = 128; // Compiler converts this line to Integer b = Integer.valueOf(128);
System.out.println(a == b); // Output -- false

但是如果我們將值賦給127兩者a並b嘗試使用相等運算符進行比較==,我們會得到true原因嗎?

Integer a = 127; // Compiler converts this line to Integer a = Integer.valueOf(127);
Integer b = 127; // Compiler converts this line to Integer b = Integer.valueOf(127);
System.out.println(a == b); // Output -- true

正如我們在,我們分配給不同的對象代碼中看到的a和b,但a == b可以返回true只有兩個a和b都指向同一個對象。

那麼比較如何才真實呢?這裡到底發生了什麼?是a和b指向同一個對象?

到目前為止,我們知道代碼Integer a = 127;是自動裝箱的一個例子,編譯器會自動將此行轉換為Integer a = Integer.valueOf(127);。

所以Integer.valueOf()這是返回這些整數對象的方法,這意味著這種方法必須在引擎蓋下做一些事情。

如果我們看一下Integer.valueOf()方法的源代碼,我們可以清楚地看到,如果傳遞的int literal i大於IntegerCache.low且小於IntegerCache.high該方法,則返回Integer對象IntegerCache。默認值IntegerCache.low和IntegerCache.high是-128和127分別。

換句話說,如果傳遞的int literal大於和小於,則Integer.valueOf()方法不是創建和返回新的整數對象,而是從內部返回Integer對象。IntegerCache``-128``127

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

Java緩存整數對象,這些對象屬於-128到127範圍,因為這個整數範圍在日常編程中被大量使用,間接節省了一些內存。

正如您在下面的圖像Integer類中看到的那樣,維護一個內部靜態IntegerCache類,它充當緩存並保存-128到127的整數對象,這就是為什麼當我們嘗試獲取整數對象時,127我們總是得到相同的對象。


Java整數緩存Integer.valueOf(127)==Integer.valueOf(127)為True


當類被加載到內存中時,緩存會在第一次使用時初始化static block。可以通過-XX:AutoBoxCacheMaxJVM選項控制緩存的最大範圍。

此緩存行為是不適用Integer的對象而已,類似於Integer.IntegerCache我們也有ByteCache,ShortCache,LongCache,CharacterCache為Byte,Short,Long,Character分別。

字節,短和長在-127到127(含)之間有一個固定的緩存範圍,但對於Character,範圍是0到127(含)。範圍只能通過參數修改為Integer而不能修改為其他範圍。

您可以在此Github存儲庫中找到本文的完整源代碼,請隨時提供寶貴的反饋。

翻譯自:https://medium.com/@njnareshjoshi/java-integer-cache-why-integer-valueof-127-integer-valueof-127-is-true-e5076824a3d5

`


分享到:


相關文章: