本文將介紹 Java 中 Integer 緩存的相關知識。這是 Java 5 中引入的一個有助於節省內存、提升性能的特性。首先看一個使用 Integer 的示例代碼,展現了 Integer 的緩存行爲。接着咱們將學習這種實現的緣由和目的。你能夠先猜猜下面 Java 程序的輸出結果。很明顯,這裏有一些小陷阱,這也是咱們寫這篇文章的緣由。html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
package
com.javapapers.java;
public
class
JavaIntegerCache {
public
static
void
main(String... strings) {
Integer integer1 =
3
;
Integer integer2 =
3
;
if
(integer1 == integer2)
System.out.println(
"integer1 == integer2"
);
else
System.out.println(
"integer1 != integer2"
);
Integer integer3 =
300
;
Integer integer4 =
300
;
if
(integer3 == integer4)
System.out.println(
"integer3 == integer4"
);
else
System.out.println(
"integer3 != integer4"
);
}
}
|
大多數人都認爲上面的兩個判斷的結果都是 false。雖然它們的值相等,但因爲比較的是對象,而對象的引用不同,因此會認爲兩個 if 判斷都是 false 的。在 Java 中,== 比較的是對象引用,而 equals 比較的是值。所以,在這個例子中,不一樣的對象有不一樣的引用,因此在進行比較的時候都應該返回 false。可是奇怪的是,這裏兩個類似的 if 條件判斷卻返回不一樣的布爾值。java
下面是上面代碼真正的輸出結果,數組
1
2
|
integer1 == integer2
integer3 != integer4
|
Java 中 Integer 緩存實現緩存
在 Java 5 中,爲 Integer 的操做引入了一個新的特性,用來節省內存和提升性能。整型對象在內部實現中經過使用相同的對象引用實現了緩存和重用。ide
上面的規則適用於整數區間 -128 到 +127。性能
這種 Integer 緩存策略僅在自動裝箱(autoboxing)的時候有用,使用構造器建立的 Integer 對象不能被緩存。學習
Java 編譯器把原始類型自動轉換爲封裝類的過程稱爲自動裝箱(autoboxing),這至關於調用 valueOf 方法ui
1
2
|
Integer a =
10
;
//this is autoboxing
Integer b = Integer.valueOf(
10
);
//under the hood
|
如今咱們知道了 JDK 源碼中對應實現的部分在哪裏了。咱們來看看 valueOf 的源碼。下面是 JDK 1.8.0 build 25 中的代碼。this
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
/**
* Returns an {<a href="http://www.jobbole.com/members/java12">@code</a> Integer} instance representing the specified
* {<a href="http://www.jobbole.com/members/java12">@code</a> int} value. If a new {<a href="http://www.jobbole.com/members/java12">@code</a> Integer} instance is not
* required, this method should generally be used in preference to
* the constructor {<a href="http://www.jobbole.com/members/57845349">@link</a> #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 {<a href="http://www.jobbole.com/members/java12">@code</a> int} value.
* @return an {<a href="http://www.jobbole.com/members/java12">@code</a> Integer} instance representing {<a href="http://www.jobbole.com/members/java12">@code</a> i}.
* <a href="http://www.jobbole.com/members/chchxinxinjun">@since</a> 1.5
*/
public
static
Integer valueOf(
int
i) {
if
(i &gt;= IntegerCache.low &amp;&amp; i &lt;= IntegerCache.high)
return
IntegerCache.cache[i + (-IntegerCache.low)];
return
new
Integer(i);
}
|
在建立新的 Integer 對象以前會先在 IntegerCache.cache 中查找。有一個專門的 Java 類來負責 Integer 的緩存。spa
IntegerCache 類
IntegerCache 是 Integer 類中一個私有的靜態類。咱們來看看這個類,有比較詳細的文檔,能夠提供咱們不少信息。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
|
/**
* 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 {<a href="http://www.jobbole.com/members/java12">@code</a> -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 &lt; cache.length; k++)
cache[k] =
new
Integer(j++);
// range [-128, 127] must be interned (JLS7 5.1.7)
assert
IntegerCache.high &gt;=
127
;
}
private
IntegerCache() {}
}
|
Javadoc 詳細的說明這個類是用來實現緩存支持,並支持 -128 到 127 之間的自動裝箱過程。最大值 127 能夠經過 JVM 的啓動參數 -XX:AutoBoxCacheMax=size 修改。 緩存經過一個 for 循環實現。從小到大的建立儘量多的整數並存儲在一個名爲 cache 的整數數組中。這個緩存會在 Integer 類第一次被使用的時候被初始化出來。之後,就可使用緩存中包含的實例對象,而不是建立一個新的實例(在自動裝箱的狀況下)。
實際上在 Java 5 中引入這個特性的時候,範圍是固定的 -128 至 +127。後來在 Java 6 中,最大值映射到 java.lang.Integer.IntegerCache.high,可使用 JVM 的啓動參數設置最大值。這使咱們能夠根據應用程序的實際狀況靈活地調整來提升性能。是什麼緣由選擇這個 -128 到 127 這個範圍呢?由於這個範圍的整數值是使用最普遍的。 在程序中第一次使用 Integer 的時候也須要必定的額外時間來初始化這個緩存。
Java 語言規範中的緩存行爲
在 Boxing Conversion 部分的Java語言規範(JLS)規定以下:
若是一個變量 p 的值屬於:-128至127之間的整數(§3.10.1),true 和 false的布爾值 (§3.10.3),’u0000′ 至 ‘u007f’ 之間的字符(§3.10.4)中時,將 p 包裝成 a 和 b 兩個對象時,能夠直接使用 a == b 判斷 a 和 b 的值是否相等。
其餘緩存的對象
這種緩存行爲不只適用於Integer對象。咱們針對全部整數類型的類都有相似的緩存機制。
有 ByteCache 用於緩存 Byte 對象
有 ShortCache 用於緩存 Short 對象
有 LongCache 用於緩存 Long 對象
有 CharacterCache 用於緩存 Character 對象
Byte,Short,Long 有固定範圍: -128 到 127。對於 Character, 範圍是 0 到 127。除了 Integer 能夠經過參數改變範圍外,其它的都不行。
原文連接: javapapers 翻譯: ImportNew.com - 挖坑的張師傅
譯文連接: http://www.importnew.com/18884.html
[ 轉載請保留原文出處、譯者和譯文連接。]