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

    xiaoxiao2021-03-25  140

    在成长中学习,在学习中成长

    分享下Java基础,感谢文章作者  http://blog.csdn.net/chengzhezhijian/article/details/9628251

    内容如下:

    [置顶] Java Integer(-128~127)值的==和equals比较产生的思考

    标签: Java Integer 5174人阅读 评论(4) 收藏 举报 分类: Java(152)

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

    [java] view plain copy System.out.println("<-128~127以内的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();  <span style="white-space:pre">      </span>  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));  

    输出结果为:

    [java] view plain copy <-128~127以内的Integer值,Integer x = value;的方式赋值!>  i=127,j =127  i == j:true<--比较-->i.equals(j):true  <-128~127以外的Integer值,Integer x = value;的方式赋值!>  m=128,n =128  m == n:false<--比较-->m.equals(n):true      <任意Integer值,Integer x = new Integer(value);的方式赋值!>  x=299,y =299  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 plain copy public class Hello    {      public static void main(String[] args)      {        int a = 1000b = 1000;        System.out.println(a == b);           Integer c = 1000d = 1000;        System.out.println(c == d);           Integer e = 100f = 100;        System.out.println(e == f);      }    }   

    输出结果:

    [html]  view plain copy true   false   true  

    The Java Language Specification, 3rd Edition 写道:

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

    查看jdk源码,如下:

    [java]  view plain copy /**       * 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>.       */          // value of java.lang.Integer.IntegerCache.high property (obtained during VM init)       private static String integerCacheHighPropValue;          static void getAndRemoveCacheProperties() {           if (!sun.misc.VM.isBooted()) {               Properties props = System.getProperties();               integerCacheHighPropValue =                   (String)props.remove("java.lang.Integer.IntegerCache.high");               if (integerCacheHighPropValue != null)                   System.setProperties(props);  // remove from system props           }       }          private static class IntegerCache {           static final int high;           static final Integer cache[];              static {               final int low = -128;                  // high value may be configured by property               int h = 127;               if (integerCacheHighPropValue != null) {                   // Use Long.decode here to avoid invoking methods that                   // require Integer's autoboxing cache to be initialized                   int i = Long.decode(integerCacheHighPropValue).intValue();                   i = Math.max(i, 127);                   // Maximum array size is Integer.MAX_VALUE                   h = Math.min(i, Integer.MAX_VALUE - -low);               }               high = h;                  cache = new Integer[(high - low) + 1];               int j = low;               for(int k = 0; k < cache.length; k++) //缓存区间数据                   cache[k] = new Integer(j++);           }              private IntegerCache() {}       }          /**       * 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       */       public static Integer valueOf(int i) {           if(i >= -128 && i <= IntegerCache.high)               return IntegerCache.cache[i + 128];           else               return new Integer(i);       }  

    这儿的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 plain copy Integer i = 100;      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 Integer i = 10000;      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++代码   // Aggressive optimization flags  -XX:+AggressiveOpts   void Arguments::set_aggressive_opts_flags() {   #ifdef COMPILER2     if (AggressiveOpts || !FLAG_IS_DEFAULT(AutoBoxCacheMax)) {       if (FLAG_IS_DEFAULT(EliminateAutoBox)) {         FLAG_SET_DEFAULT(EliminateAutoBox, true);       }       if (FLAG_IS_DEFAULT(AutoBoxCacheMax)) {         FLAG_SET_DEFAULT(AutoBoxCacheMax, 20000);       }          // Feed the cache size setting into the JDK       char buffer[1024];       sprintf(buffer, "java.lang.Integer.IntegerCache.high=" INTX_FORMAT, AutoBoxCacheMax);       add_property(buffer);     }     // ...   #endif   }   测试代码:  Java代码   // run with:   // java -server -XX:AutoBoxCacheMax=1000 TestAutoBoxCache      public class TestAutoBoxCache {       public static void main(String[] args) {           Integer a = 1000;           Integer b = 1000;           System.out.println(a == b);                      Integer c = 1001;           Integer d = 1001;           System.out.println(c == d);                      Integer e = 20000;           Integer f = 20000;           System.out.println(e == f);       }   }   在命令行上测试:  Command prompt代码   D:\>javac TestAutoBoxCache.java      D:\>java TestAutoBoxCache   false   false   false      D:\>java -server TestAutoBoxCache   false   false   false      D:\>java -Djava.lang.Integer.IntegerCache.high=1000 TestAutoBoxCache   true   false   false      D:\>java -server -Djava.lang.Integer.IntegerCache.high=1000 TestAutoBoxCache   true   false   false      D:\>java -Djava.lang.Integer.IntegerCache.high=1001 TestAutoBoxCache   true   true   false      D:\>java -server -Djava.lang.Integer.IntegerCache.high=1001 TestAutoBoxCache   true   true   false      D:\>java -XX:AutoBoxCacheMax=1000 TestAutoBoxCache   Unrecognized VM option 'AutoBoxCacheMax=1000'   Could not create the Java virtual machine.      D:\>java -server -XX:AutoBoxCacheMax=1000 TestAutoBoxCache   true   false   false      D:\>java -server -XX:AutoBoxCacheMax=1001 TestAutoBoxCache   true   true   false      D:\>java -server -XX:+AggressiveOpts TestAutoBoxCache   true   true   true   中间报 Unrecognized VM option 'AutoBoxCacheMax=1000' 错误是因为这个参数只能在HotSpot Server VM上使用,在HotSpot Client VM上不支持。

    转载请注明原文地址: https://ju.6miu.com/read-11748.html

    最新回复(0)