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

最近在項目中遇到一個問題,兩個值相同的Integer型值進行==比較時,發現Integer其中的一些奧祕,順便也複習一下==和equals的區別,先經過Damo代碼解釋以下:html

 

[java]  view plain  copy
 
 在CODE上查看代碼片派生到個人代碼片
  1. System.out.println("<-128~127之內的Integer值,Integer x = value;的方式賦值!>");  
  2. Integer i = 127;  
  3. Integer j = 127;  
  4. System.out.println("i=" + i + ",j =" + j);  
  5. System.out.println("i == j:" + (i == j) + "<--比較-->i.equals(j):"+ i.equals(j));  
  6. System.out.println("<-128~127之外的Integer值,Integer x = value;的方式賦值!>");  
  7. Integer m = 128;  
  8. Integer n = 128;  
  9. System.out.println("m=" + m + ",n =" + n);  
  10. System.out.println("m == n:" + (m == n) + "<--比較-->m.equals(n):"+ m.equals(n));  
  11. System.out.println();  
  12. <span style="white-space:pre">      </span>  
  13. System.out.println("<任意Integer值,Integer x = new Integer(value);的方式賦值!>");  
  14. Integer x = new Integer(299);  
  15. Integer y = new Integer(299);  
  16. System.out.println("x=" + x + ",y =" + y);  
  17. System.out.println("x == y:" + (x == y) + "<--比較-->x.equals(y):"+ x.equals(y));  

 

 

輸出結果爲:java

 

[java]  view plain  copy
 
 在CODE上查看代碼片派生到個人代碼片
  1. <-128~127之內的Integer值,Integer x = value;的方式賦值!>  
  2. i=127,j =127  
  3. i == j:true<--比較-->i.equals(j):true  
  4. <-128~127之外的Integer值,Integer x = value;的方式賦值!>  
  5. m=128,n =128  
  6. m == n:false<--比較-->m.equals(n):true  
  7.   
  8.   
  9. <任意Integer值,Integer x = new Integer(value);的方式賦值!>  
  10. x=299,y =299  
  11. x == y:false<--比較-->x.equals(y):true  

 

 

 

經過以上代碼及輸出結果,想必你們已經看出其中奧祕!先總結以下:
一、以上代碼第一段和第二段旨在說明:在-128~127的Integer值而且以Integer x = value;的方式賦值的Integer值在進行==和equals比較時,都會返回true,由於Java裏面對處在在-128~127之間的Integer值,用的是原生數據類型int,會在內存裏供重用,也就是說這之間的Integer值進行==比較時只是進行int原生數據類型的數值比較,而超出-128~127的範圍,進行==比較時是進行地址及數值比較。


二、第三段旨在說明:==和equals的區別,==是進行地址及值比較,沒法對==操做符進行重載,而對於equals方法,Integer裏面的equals方法重寫了Object的equals方法,查看Integer源碼能夠看出equals方法進行的是數值比較。

續詳解:數組

 

 首先看一段代碼(使用JDK 5),以下:緩存

[html]  view plain copy
 
 
  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.   
  8.     Integer c = 1000, d = 1000;   
  9.     System.out.println(c == d);   
  10.   
  11.     Integer e = 100, f = 100;   
  12.     System.out.println(e == f);   
  13.   }   
  14. }   

輸出結果:ide

[html]  view plain copy
 
 
  1. true  
  2. false  
  3. true  

The Java Language Specification, 3rd Edition 寫道:測試

[html]  view plain copy
 
 
  1. 爲了節省內存,對於下列包裝對象的兩個實例,當它們的基本值相同時,他們老是==:  
  2.  Boolean  
  3.  Byte  
  4.  Character, \u0000 - \u007f(7f是十進制的127)  
  5.  Integer, -128 — 127  

查看jdk源碼,以下:ui

[java]  view plain copy
 
 
  1. /** 
  2.      * Cache to support the object identity semantics of autoboxing for values between  
  3.      * -128 and 127 (inclusive) as required by JLS. 
  4.      * 
  5.      * The cache is initialized on first usage. During VM initialization the 
  6.      * getAndRemoveCacheProperties method may be used to get and remove any system 
  7.      * properites that configure the cache size. At this time, the size of the 
  8.      * cache may be controlled by the vm option -XX:AutoBoxCacheMax=<size>. 
  9.      */  
  10.   
  11.     // value of java.lang.Integer.IntegerCache.high property (obtained during VM init)  
  12.     private static String integerCacheHighPropValue;  
  13.   
  14.     static void getAndRemoveCacheProperties() {  
  15.         if (!sun.misc.VM.isBooted()) {  
  16.             Properties props = System.getProperties();  
  17.             integerCacheHighPropValue =  
  18.                 (String)props.remove("java.lang.Integer.IntegerCache.high");  
  19.             if (integerCacheHighPropValue != null)  
  20.                 System.setProperties(props);  // remove from system props  
  21.         }  
  22.     }  
  23.   
  24.     private static class IntegerCache {  
  25.         static final int high;  
  26.         static final Integer cache[];  
  27.   
  28.         static {  
  29.             final int low = -128;  
  30.   
  31.             // high value may be configured by property  
  32.             int h = 127;  
  33.             if (integerCacheHighPropValue != null) {  
  34.                 // Use Long.decode here to avoid invoking methods that  
  35.                 // require Integer's autoboxing cache to be initialized  
  36.                 int i = Long.decode(integerCacheHighPropValue).intValue();  
  37.                 i = Math.max(i, 127);  
  38.                 // Maximum array size is Integer.MAX_VALUE  
  39.                 h = Math.min(i, Integer.MAX_VALUE - -low);  
  40.             }  
  41.             high = h;  
  42.   
  43.             cache = new Integer[(high - low) + 1];  
  44.             int j = low;  
  45.             for(int k = 0; k < cache.length; k++) //緩存區間數據  
  46.                 cache[k] = new Integer(j++);  
  47.         }  
  48.   
  49.         private IntegerCache() {}  
  50.     }  
  51.   
  52.     /** 
  53.      * Returns a <tt>Integer</tt> instance representing the specified 
  54.      * <tt>int</tt> value. 
  55.      * If a new <tt>Integer</tt> instance is not required, this method 
  56.      * should generally be used in preference to the constructor 
  57.      * {@link #Integer(int)}, as this method is likely to yield 
  58.      * significantly better space and time performance by caching 
  59.      * frequently requested values. 
  60.      * 
  61.      * @param  i an <code>int</code> value. 
  62.      * @return a <tt>Integer</tt> instance representing <tt>i</tt>. 
  63.      * @since  1.5 
  64.      */  
  65.     public static Integer valueOf(int i) {  
  66.         if(i >= -128 && i <= IntegerCache.high)  
  67.             return IntegerCache.cache[i + 128];  
  68.         else  
  69.             return new Integer(i);  
  70.     }  

這兒的IntegerCache有一個靜態的Integer數組,在類加載時就將-128 到 127 的Integer對象建立了,並保存在cache數組中,一旦程序調用valueOf 方法,若是i的值是在-128 到 127 之間就直接在cache緩存數組中去取Integer對象。this

再看其它的包裝器:spa

 

  • Boolean:(所有緩存)
  • Byte:(所有緩存)
  • Character(<= 127緩存)
  • Short(-128 — 127緩存)
  • Long(-128 — 127緩存)
  • Float(沒有緩存)
  • Doulbe(沒有緩存)

 

 

一樣對於垃圾回收器來講:.net

[java]  view plain copy
 
 
  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 plain copy
 
 
  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語言規範第三版,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.

這就是爲何符合規範的Java實現必須保證Integer的緩存至少要覆蓋[-128, 127]的範圍。 

使用Oracle/Sun JDK 6,在server模式下,使用-XX:AutoBoxCacheMax=NNN參數便可將Integer的自動緩存區間設置爲[-128,NNN]。注意區間的下界固定在-128不可配置。 
在client模式下該參數無效。這個參數是server模式專有的,在 c2_globals.hpp中聲明,默認值是128;不過這個默認值在默認條件下不起做用,要手動設置它的值或者是開啓-XX:+AggressiveOpts參數才起做用。 

在設置了-XX:+AggressiveOpts啓動參數後,AutoBoxCacheMax的默認值會被修改成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.   
  12.     // Feed the cache size setting into the JDK  
  13.     char buffer[1024];  
  14.     sprintf(buffer, "java.lang.Integer.IntegerCache.high=" INTX_FORMAT, AutoBoxCacheMax);  
  15.     add_property(buffer);  
  16.   }  
  17.   // ...  
  18. #endif  
  19. }  


測試代碼: 
Java代碼   收藏代碼
  1. // run with:  
  2. // java -server -XX:AutoBoxCacheMax=1000 TestAutoBoxCache  
  3.   
  4. public class TestAutoBoxCache {  
  5.     public static void main(String[] args) {  
  6.         Integer a = 1000;  
  7.         Integer b = 1000;  
  8.         System.out.println(a == b);  
  9.           
  10.         Integer c = 1001;  
  11.         Integer d = 1001;  
  12.         System.out.println(c == d);  
  13.           
  14.         Integer e = 20000;  
  15.         Integer f = 20000;  
  16.         System.out.println(e == f);  
  17.     }  
  18. }  


在命令行上測試: 
Command prompt代碼   收藏代碼
  1. D:\>javac TestAutoBoxCache.java  
  2.   
  3. D:\>java TestAutoBoxCache  
  4. false  
  5. false  
  6. false  
  7.   
  8. D:\>java -server TestAutoBoxCache  
  9. false  
  10. false  
  11. false  
  12.   
  13. D:\>java -Djava.lang.Integer.IntegerCache.high=1000 TestAutoBoxCache  
  14. true  
  15. false  
  16. false  
  17.   
  18. D:\>java -server -Djava.lang.Integer.IntegerCache.high=1000 TestAutoBoxCache  
  19. true  
  20. false  
  21. false  
  22.   
  23. D:\>java -Djava.lang.Integer.IntegerCache.high=1001 TestAutoBoxCache  
  24. true  
  25. true  
  26. false  
  27.   
  28. D:\>java -server -Djava.lang.Integer.IntegerCache.high=1001 TestAutoBoxCache  
  29. true  
  30. true  
  31. false  
  32.   
  33. D:\>java -XX:AutoBoxCacheMax=1000 TestAutoBoxCache  
  34. Unrecognized VM option 'AutoBoxCacheMax=1000'  
  35. Could not create the Java virtual machine.  
  36.   
  37. D:\>java -server -XX:AutoBoxCacheMax=1000 TestAutoBoxCache  
  38. true  
  39. false  
  40. false  
  41.   
  42. D:\>java -server -XX:AutoBoxCacheMax=1001 TestAutoBoxCache  
  43. true  
  44. true  
  45. false  
  46.   
  47. D:\>java -server -XX:+AggressiveOpts TestAutoBoxCache  
  48. true  
  49. true  
  50. true  

中間報Unrecognized VM option 'AutoBoxCacheMax=1000'錯誤是由於這個參數只能在HotSpot Server VM上使用,在HotSpot Client VM上不支持。
 
 摘自:http://blog.csdn.net/chengzhezhijian/article/details/9628251
相關文章
相關標籤/搜索