美文网首页
Java Integer(-128~127)值的==和equal

Java Integer(-128~127)值的==和equal

作者: 编码前线 | 来源:发表于2018-08-16 23:32 被阅读90次

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

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

    输出结果为:

    <-128~127以内的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
    

    通过以上代码及输出结果,想必大家已经看出其中奥秘!先总结如下:

    1、以上代码第一段和第二段旨在说明:在-128~127的Integer值并且以Integer x = value;的方式赋值的Integer值在进行==和equals比较时,都会返回true,因为Java里面对处在在-128127之间的Integer值,用的是原生数据类型int,会在内存里供重用,也就是说这之间的Integer值进行==比较时只是进行int原生数据类型的数值比较,而超出-128127的范围,进行==比较时是进行地址及数值比较。

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

    续详解:

    首先看一段代码(使用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. }

    输出结果:

    1. true

    2. false

    3. true

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

    1. 为了节省内存,对于下列包装对象的两个实例,当它们的基本值相同时,他们总是==:

    2. Boolean

    3. Byte

    4. Character, \u0000 - \u007f(7f是十进制的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++) //缓存区间数据

    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有一个静态的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. // 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

    相关文章

      网友评论

          本文标题:Java Integer(-128~127)值的==和equal

          本文链接:https://www.haomeiwen.com/subject/afuabftx.html