Java Integer(-128~127)值的==和equals比較產(chǎn)生的思考

最近在項(xiàng)目中遇到一個問題,兩個值相同的Integer型值進(jìn)行==比較時氛悬,發(fā)現(xiàn)Integer其中的一些奧秘,順便也復(fù)習(xí)一下==和equals的區(qū)別,先通過Damo代碼解釋如下:

System.out.println("<-128~127以內(nèi)的Integer值俄占,Integer x = value;的方式賦值!>");Integer i = 127;Integer j = 127;System.out.println("i=" + i + ",j =" + j);System.out.println("i == j:" + (i == j) + "<--比較-->i.equals(j):"+ i.equals(j));System.out.println("<-128~127以外的Integer值淆衷,Integer x = value;的方式賦值缸榄!>");Integer m = 128;Integer n = 128;System.out.println("m=" + m + ",n =" + n);System.out.println("m == n:" + (m == n) + "<--比較-->m.equals(n):"+ m.equals(n));System.out.println();       System.out.println("<任意Integer值,Integer x = new Integer(value);的方式賦值祝拯!>");Integer x = new Integer(299);Integer y = new Integer(299);System.out.println("x=" + x + ",y =" + y);System.out.println("x == y:" + (x == y) + "<--比較-->x.equals(y):"+ x.equals(y));

輸出結(jié)果為:

<-128~127以內(nèi)的Integer值甚带,Integer x = value;的方式賦值!>i=127,j =127i == j:true<--比較-->i.equals(j):true<-128~127以外的Integer值鹿驼,Integer x = value;的方式賦值欲低!>m=128,n =128m == n:false<--比較-->m.equals(n):true<任意Integer值,Integer x = new Integer(value);的方式賦值畜晰!>x=299,y =299x == y:false<--比較-->x.equals(y):true

通過以上代碼及輸出結(jié)果砾莱,想必大家已經(jīng)看出其中奧秘!先總結(jié)如下:

1凄鼻、以上代碼第一段和第二段旨在說明:在-128~127的Integer值并且以Integer x = value;的方式賦值的Integer值在進(jìn)行==和equals比較時腊瑟,都會返回true聚假,因?yàn)镴ava里面對處在在-128127之間的Integer值,用的是原生數(shù)據(jù)類型int闰非,會在內(nèi)存里供重用膘格,也就是說這之間的Integer值進(jìn)行==比較時只是進(jìn)行int原生數(shù)據(jù)類型的數(shù)值比較,而超出-128127的范圍财松,進(jìn)行==比較時是進(jìn)行地址及數(shù)值比較瘪贱。

2、第三段旨在說明:==和equals的區(qū)別辆毡,==是進(jìn)行地址及值比較菜秦,無法對==操作符進(jìn)行重載,而對于equals方法舶掖,Integer里面的equals方法重寫了Object的equals方法球昨,查看Integer源碼可以看出equals方法進(jìn)行的是數(shù)值比較。

續(xù)詳解:

首先看一段代碼(使用JDK 5)眨攘,如下:

  1. public class Hello

  2. {

  3. public static void main(String[] args)

  4. {

  5. int a = 1000, b = 1000;

  6. System.out.println(a == b);

  7. Integer c = 1000, d = 1000;

  8. System.out.println(c == d);

  9. Integer e = 100, f = 100;

  10. System.out.println(e == f);

  11. }

  12. }

輸出結(jié)果:

  1. true

  2. false

  3. true

The Java Language Specification, 3rd Edition 寫道: view plaincopy

  1. 為了節(jié)省內(nèi)存主慰,對于下列包裝對象的兩個實(shí)例,當(dāng)它們的基本值相同時鲫售,他們總是==:

  2. Boolean

  3. Byte

  4. Character, \u0000 - \u007f(7f是十進(jìn)制的127)

  5. Integer, -128 — 127

查看jdk源碼共螺,如下:

[java] view plaincopy

  1. /**

    • 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. During VM initialization the
    • getAndRemoveCacheProperties method may be used to get and remove any system
    • properites that configure the cache size. At this time, the size of the
    • cache may be controlled by the vm option -XX:AutoBoxCacheMax=<size>.
  2. */

  3. // value of java.lang.Integer.IntegerCache.high property (obtained during VM init)

  4. private static String integerCacheHighPropValue;

  5. static void getAndRemoveCacheProperties() {

  6. if (!sun.misc.VM.isBooted()) {

  7. Properties props = System.getProperties();

  8. integerCacheHighPropValue =

  9. (String)props.remove("java.lang.Integer.IntegerCache.high");

  10. if (integerCacheHighPropValue != null)

  11. System.setProperties(props); // remove from system props

  12. }

  13. }

  14. private static class IntegerCache {

  15. static final int high;

  16. static final Integer cache[];

  17. static {

  18. final int low = -128;

  19. // high value may be configured by property

  20. int h = 127;

  21. if (integerCacheHighPropValue != null) {

  22. // Use Long.decode here to avoid invoking methods that

  23. // require Integer's autoboxing cache to be initialized

  24. int i = Long.decode(integerCacheHighPropValue).intValue();

  25. i = Math.max(i, 127);

  26. // Maximum array size is Integer.MAX_VALUE

  27. h = Math.min(i, Integer.MAX_VALUE - -low);

  28. }

  29. high = h;

  30. cache = new Integer[(high - low) + 1];

  31. int j = low;

  32. for(int k = 0; k < cache.length; k++) //緩存區(qū)間數(shù)據(jù)

  33. cache[k] = new Integer(j++);

  34. }

  35. private IntegerCache() {}

  36. }

  37. /**

    • Returns a <tt>Integer</tt> instance representing the specified
    • <tt>int</tt> value.
    • If a new <tt>Integer</tt> 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.
    • @param i an <code>int</code> value.
    • @return a <tt>Integer</tt> instance representing <tt>i</tt>.
    • @since 1.5
  38. */

  39. public static Integer valueOf(int i) {

  40. if(i >= -128 && i <= IntegerCache.high)

  41. return IntegerCache.cache[i + 128];

  42. else

  43. return new Integer(i);

  44. }

這兒的IntegerCache有一個靜態(tài)的Integer數(shù)組,在類加載時就將-128 到 127 的Integer對象創(chuàng)建了龟虎,并保存在cache數(shù)組中璃谨,一旦程序調(diào)用valueOf 方法,如果i的值是在-128 到 127 之間就直接在cache緩存數(shù)組中去取Integer對象鲤妥。

再看其它的包裝器:

  Boolean:(全部緩存)
  • Byte:(全部緩存)

  • Character(<= 127緩存)

  • Short(-128 — 127緩存)

  • Long(-128 — 127緩存)

  • Float(沒有緩存)

  • Doulbe(沒有緩存)

同樣對于垃圾回收器來說:

[java] view plaincopy

  1. Integer i = 100;

  2. i = null;//will not make any object available for GC at all.

這里的代碼不會有對象符合垃圾回收器的條件佳吞,這兒的i雖然被賦予null,但它之前指向的是cache中的Integer對象棉安,而cache沒有被賦null底扳,所以Integer(100)這個對象還是存在盒件。

而如果i大于127或小于-128則它所指向的對象將符合垃圾回收的條件:

[java] view plaincopy

  1. Integer i = 10000;

  2. i = null;//will make the newly created Integer object available for GC.

那么緩存如何修改呢见咒?

下面例子使用32位Windows上的Sun JDK 1.6.0 update 18。

在Java語言規(guī)范第三版朋凉,5.1.7 Boxing Conversion中蒲赂,

The Java Language Specification, 3rd Edition 寫道

If the value p being boxed is true, false, a byte, a char in the range \u0000 to \u007f, or an int or short number between -128 and 127, then let r1 and r2 be the results of any two boxing conversions of p. It is always the case that r1 == r2.

這就是為什么符合規(guī)范的Java實(shí)現(xiàn)必須保證Integer的緩存至少要覆蓋[-128, 127]的范圍阱冶。

使用Oracle/Sun JDK 6,在server模式下滥嘴,使用-XX:AutoBoxCacheMax=NNN參數(shù)即可將Integer的自動緩存區(qū)間設(shè)置為[-128,NNN]木蹬。注意區(qū)間的下界固定在-128不可配置。
在client模式下該參數(shù)無效若皱。這個參數(shù)是server模式專有的镊叁,在c2_globals.hpp中聲明尘颓,默認(rèn)值是128;不過這個默認(rèn)值在默認(rèn)條件下不起作用晦譬,要手動設(shè)置它的值或者是開啟-XX:+AggressiveOpts參數(shù)才起作用疤苹。

在設(shè)置了-XX:+AggressiveOpts啟動參數(shù)后,AutoBoxCacheMax的默認(rèn)值會被修改為20000并且生效敛腌。參考arguments.cpp:

C++代碼

  1. // Aggressive optimization flags -XX:+AggressiveOpts

  2. void Arguments::set_aggressive_opts_flags() {

  3. ifdef COMPILER2

  4. if (AggressiveOpts || !FLAG_IS_DEFAULT(AutoBoxCacheMax)) {

  5. if (FLAG_IS_DEFAULT(EliminateAutoBox)) {

  6. FLAG_SET_DEFAULT(EliminateAutoBox, true);

  7. }

  8. if (FLAG_IS_DEFAULT(AutoBoxCacheMax)) {

  9. FLAG_SET_DEFAULT(AutoBoxCacheMax, 20000);

  10. }

  11. // Feed the cache size setting into the JDK

  12. char buffer[1024];

  13. sprintf(buffer, "java.lang.Integer.IntegerCache.high=" INTX_FORMAT, AutoBoxCacheMax);

  14. add_property(buffer);

  15. }

  16. // ...

  17. endif

  18. }

測試代碼:

Java代碼

  1. // run with:

  2. // java -server -XX:AutoBoxCacheMax=1000 TestAutoBoxCache

  3. public class TestAutoBoxCache {

  4. public static void main(String[] args) {

  5. Integer a = 1000;

  6. Integer b = 1000;

  7. System.out.println(a == b);

  8. Integer c = 1001;

  9. Integer d = 1001;

  10. System.out.println(c == d);

  11. Integer e = 20000;

  12. Integer f = 20000;

  13. System.out.println(e == f);

  14. }

  15. }

在命令行上測試:

Command prompt代碼

  1. D:>javac TestAutoBoxCache.java

  2. D:>java TestAutoBoxCache

  3. false

  4. false

  5. false

  6. D:>java -server TestAutoBoxCache

  7. false

  8. false

  9. false

  10. D:>java -Djava.lang.Integer.IntegerCache.high=1000 TestAutoBoxCache

  11. true

  12. false

  13. false

  14. D:>java -server -Djava.lang.Integer.IntegerCache.high=1000 TestAutoBoxCache

  15. true

  16. false

  17. false

  18. D:>java -Djava.lang.Integer.IntegerCache.high=1001 TestAutoBoxCache

  19. true

  20. true

  21. false

  22. D:>java -server -Djava.lang.Integer.IntegerCache.high=1001 TestAutoBoxCache

  23. true

  24. true

  25. false

  26. D:>java -XX:AutoBoxCacheMax=1000 TestAutoBoxCache

  27. Unrecognized VM option 'AutoBoxCacheMax=1000'

  28. Could not create the Java virtual machine.

  29. D:>java -server -XX:AutoBoxCacheMax=1000 TestAutoBoxCache

  30. true

  31. false

  32. false

  33. D:>java -server -XX:AutoBoxCacheMax=1001 TestAutoBoxCache

  34. true

  35. true

  36. false

  37. D:>java -server -XX:+AggressiveOpts TestAutoBoxCache

  38. true

  39. true

  40. true

image
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末卧土,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子像樊,更是在濱河造成了極大的恐慌夸溶,老刑警劉巖,帶你破解...
    沈念sama閱讀 222,252評論 6 516
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件凶硅,死亡現(xiàn)場離奇詭異,居然都是意外死亡扫皱,警方通過查閱死者的電腦和手機(jī)足绅,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,886評論 3 399
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來韩脑,“玉大人氢妈,你說我怎么就攤上這事《味啵” “怎么了首量?”我有些...
    開封第一講書人閱讀 168,814評論 0 361
  • 文/不壞的土叔 我叫張陵,是天一觀的道長进苍。 經(jīng)常有香客問我加缘,道長,這世上最難降的妖魔是什么觉啊? 我笑而不...
    開封第一講書人閱讀 59,869評論 1 299
  • 正文 為了忘掉前任拣宏,我火速辦了婚禮,結(jié)果婚禮上杠人,老公的妹妹穿的比我還像新娘勋乾。我一直安慰自己,他們只是感情好嗡善,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,888評論 6 398
  • 文/花漫 我一把揭開白布辑莫。 她就那樣靜靜地躺著,像睡著了一般罩引。 火紅的嫁衣襯著肌膚如雪各吨。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,475評論 1 312
  • 那天蜒程,我揣著相機(jī)與錄音绅你,去河邊找鬼伺帘。 笑死,一個胖子當(dāng)著我的面吹牛忌锯,可吹牛的內(nèi)容都是我干的伪嫁。 我是一名探鬼主播,決...
    沈念sama閱讀 41,010評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼偶垮,長吁一口氣:“原來是場噩夢啊……” “哼张咳!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起似舵,我...
    開封第一講書人閱讀 39,924評論 0 277
  • 序言:老撾萬榮一對情侶失蹤脚猾,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后砚哗,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體龙助,經(jīng)...
    沈念sama閱讀 46,469評論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,552評論 3 342
  • 正文 我和宋清朗相戀三年蛛芥,在試婚紗的時候發(fā)現(xiàn)自己被綠了提鸟。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,680評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡仅淑,死狀恐怖称勋,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情涯竟,我是刑警寧澤赡鲜,帶...
    沈念sama閱讀 36,362評論 5 351
  • 正文 年R本政府宣布,位于F島的核電站庐船,受9級特大地震影響银酬,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜筐钟,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,037評論 3 335
  • 文/蒙蒙 一捡硅、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧盗棵,春花似錦壮韭、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,519評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至瞭恰,卻和暖如春屯曹,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,621評論 1 274
  • 我被黑心中介騙來泰國打工恶耽, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留密任,地道東北人。 一個月前我還...
    沈念sama閱讀 49,099評論 3 378
  • 正文 我出身青樓偷俭,卻偏偏與公主長得像浪讳,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子涌萤,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,691評論 2 361

推薦閱讀更多精彩內(nèi)容