Java 中整型的緩存機(jī)制

本文將介紹Java中Integer的緩存相關(guān)知識(shí)。這是在Java 5中引入的一個(gè)有助于節(jié)省內(nèi)存、提高性能的功能。首先看一個(gè)使用Integer的示例代碼,從中學(xué)習(xí)其緩存行為。接著我們將為什么這么實(shí)現(xiàn)以及他到底是如何實(shí)現(xiàn)的。你能猜出下面的Java程序的輸出結(jié)果嗎。如果你的結(jié)果和真正結(jié)果不一樣,那么你就要好好看看本文了。

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

? ? }

}

我們普遍認(rèn)為上面的兩個(gè)判斷的結(jié)果都是false。雖然比較的值是相等的,但是由于比較的是對(duì)象,而對(duì)象的引用不一樣,所以會(huì)認(rèn)為兩個(gè)if判斷都是false的。在Java中,==比較的是對(duì)象應(yīng)用,而equals比較的是值。所以,在這個(gè)例子中,不同的對(duì)象有不同的引用,所以在進(jìn)行比較的時(shí)候都將返回false。奇怪的是,這里兩個(gè)類(lèi)似的if條件判斷返回不同的布爾值。

上面這段代碼真正的輸出結(jié)果:

integer1 == integer2

integer3 != integer4

Java中Integer的緩存實(shí)現(xiàn)

在Java 5中,在Integer的操作上引入了一個(gè)新功能來(lái)節(jié)省內(nèi)存和提高性能。整型對(duì)象通過(guò)使用相同的對(duì)象引用實(shí)現(xiàn)了緩存和重用。

適用于整數(shù)值區(qū)間-128 至 +127。

只適用于自動(dòng)裝箱。使用構(gòu)造函數(shù)創(chuàng)建對(duì)象不適用。

Java的編譯器把基本數(shù)據(jù)類(lèi)型自動(dòng)轉(zhuǎn)換成封裝類(lèi)對(duì)象的過(guò)程叫做自動(dòng)裝箱,相當(dāng)于使用valueOf方法:

Integer a = 10; //this is autoboxing

Integer b = Integer.valueOf(10); //under the hood

現(xiàn)在我們知道了這種機(jī)制在源碼中哪里使用了,那么接下來(lái)我們就看看JDK中的valueOf方法。下面是JDK 1.8.0 build 25的實(shí)現(xiàn):

/**

? ? ?* 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);

? ? }

在創(chuàng)建對(duì)象之前先從IntegerCache.cache中尋找。如果沒(méi)找到才使用new新建對(duì)象。

IntegerCache Class

IntegerCache是Integer類(lèi)中定義的一個(gè)private static的內(nèi)部類(lèi)。接下來(lái)看看他的定義。

/**

? ?* 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() {}

? }

其中的javadoc詳細(xì)的說(shuō)明了緩存支持-128到127之間的自動(dòng)裝箱過(guò)程。最大值127可以通過(guò)-XX:AutoBoxCacheMax=size修改。 緩存通過(guò)一個(gè)for循環(huán)實(shí)現(xiàn)。從低到高并創(chuàng)建盡可能多的整數(shù)并存儲(chǔ)在一個(gè)整數(shù)數(shù)組中。這個(gè)緩存會(huì)在Integer類(lèi)第一次被使用的時(shí)候被初始化出來(lái)。以后,就可以使用緩存中包含的實(shí)例對(duì)象,而不是創(chuàng)建一個(gè)新的實(shí)例(在自動(dòng)裝箱的情況下)。

實(shí)際上這個(gè)功能在Java 5中引入的時(shí)候,范圍是固定的-128 至 +127。后來(lái)在Java 6中,可以通過(guò)java.lang.Integer.IntegerCache.high設(shè)置最大值。這使我們可以根據(jù)應(yīng)用程序的實(shí)際情況靈活地調(diào)整來(lái)提高性能。到底是什么原因選擇這個(gè)-128到127范圍呢?因?yàn)檫@個(gè)范圍的數(shù)字是最被廣泛使用的。 在程序中,第一次使用Integer的時(shí)候也需要一定的額外時(shí)間來(lái)初始化這個(gè)緩存。

Java語(yǔ)言規(guī)范中的緩存行為

在Boxing Conversion部分的Java語(yǔ)言規(guī)范(JLS)規(guī)定如下:

如果一個(gè)變量p的值是:

-128至127之間的整數(shù)(§3.10.1)

true 和 false的布爾值 (§3.10.3)

‘\u0000’至 ‘\u007f’之間的字符(§3.10.4)

中時(shí),將p包裝成a和b兩個(gè)對(duì)象時(shí),可以直接使用a==b判斷a和b的值是否相等。

其他緩存的對(duì)象

這種緩存行為不僅適用于Integer對(duì)象。我們針對(duì)所有的整數(shù)類(lèi)型的類(lèi)都有類(lèi)似的緩存機(jī)制。

有ByteCache用于緩存Byte對(duì)象

有ShortCache用于緩存Short對(duì)象

有LongCache用于緩存Long對(duì)象

有CharacterCache用于緩存Character對(duì)象

Byte, Short, Long有固定范圍: -128 到 127。對(duì)于Character, 范圍是 0 到 127。除了Integer以外,這個(gè)范圍都不能改變。

來(lái)源:張洪亮,

www.hollischuang.com/archives/1174

如果有其他疑問(wèn)或是看法可以在評(píng)論里或投稿跟小編進(jìn)行討論,也可以關(guān)注微信公眾號(hào)【潭州筑夢(mèng)Java】進(jìn)行投稿,與小編一起探討更多的編程知識(shí)。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 本文將介紹Java中Integer的緩存相關(guān)知識(shí)。這是在Java 5中引入的一個(gè)有助于節(jié)省內(nèi)存、提高性能的功能。首...
    墨雨軒夏閱讀 565評(píng)論 0 10
  • 英文原文:Java Integer Cache 翻譯地址:Java中整型的緩存機(jī)制 原文作者:Java Paper...
    人在碼途閱讀 1,058評(píng)論 0 0
  • 1、 什么是包裝類(lèi) 包裝類(lèi)就是Java基本數(shù)據(jù)類(lèi)型的對(duì)象表示形式。其中包括基本數(shù)據(jù)類(lèi)型byte, char, sh...
    otmoc閱讀 492評(píng)論 0 0
  • 最近在項(xiàng)目中遇到一個(gè)問(wèn)題,兩個(gè)值相同的Integer型值進(jìn)行==比較時(shí),發(fā)現(xiàn)Integer其中的一些奧秘,順便也復(fù)...
    編碼前線閱讀 780評(píng)論 0 0
  • 自動(dòng)裝箱和拆箱從Java 1.5開(kāi)始引入,目的是將原始類(lèi)型值轉(zhuǎn)自動(dòng)地轉(zhuǎn)換成對(duì)應(yīng)的對(duì)象。自動(dòng)裝箱與拆箱的機(jī)制可以讓我...
    codersm閱讀 453評(píng)論 0 0

友情鏈接更多精彩內(nèi)容