• Java Integer(-128~127)值的==和equals比较产生的思考


    最近在项目中遇到一个问题,两个值相同的Integer型值进行==比较时,发现Integer其中的一些奥秘,顺便也复习一下==和equals的区别,先通过Damo代码解释如下:

    [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] 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  
    通过以上代码及输出结果,想必大家已经看出其中奥秘!先总结如下:
    1、以上代码第一段和第二段旨在说明:在-128~127的Integer值并且以Integer x = value;的方式赋值的Integer值在进行==和equals比较时,都会返回true,因为Java里面对处在在-128~127之间的Integer值,用的是原生数据类型int,会在内存里供重用,也就是说这之间的Integer值进行==比较时只是进行int原生数据类型的数值比较,而超出-128~127的范围,进行==比较时是进行地址及数值比较。


    2、第三段旨在说明:==和equals的区别,==是进行地址及值比较,无法对==操作符进行重载,而对于equals方法,Integer里面的equals方法重写了Object的equals方法,查看Integer源码可以看出equals方法进行的是数值比较。

    续详解:

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

    [html] view plaincopy
     
     
    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. }   

    输出结果:

    [html] view plaincopy
     
     
    1. true  
    2. false  
    3. true  

    The Java Language Specification, 3rd Edition 写道:

    [html] view plaincopy
     
     
    1. 为了节省内存,对于下列包装对象的两个实例,当它们的基本值相同时,他们总是==:  
    2.  Boolean  
    3.  Byte  
    4.  Character, u0000 - u007f(7f是十进制的127)  
    5.  Integer, -128 — 127  

    查看jdk源码,如下:

    [java] view plaincopy
     
     
    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对象。

    再看其它的包装器:

    • 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语言规范第三版,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
  • 相关阅读:
    Docker安装及简单使用
    常用编程语言注释符
    常用正则标记
    Android studio 使用startService报错:IllegalStateException
    Mybatis映射文件中#取值时指定参数相关规则
    IDEA Maven项目的Mybatis逆向工程
    循环结构
    每日思考(2020/03/05)
    分支结构
    每日思考(2020/03/04)
  • 原文地址:https://www.cnblogs.com/csniper/p/5882760.html
Copyright © 2020-2023  润新知