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

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

[java] view plain copy

  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

  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. <任意Integer值,Integer x = new Integer(value);的方式赋值!>
  8. x=299,y =299
  9. 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. 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. }

输出结果:

[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. // value of java.lang.Integer.IntegerCache.high property (obtained during VM init)
  11. private static String integerCacheHighPropValue;
  12. static void getAndRemoveCacheProperties() {
  13. if (!sun.misc.VM.isBooted()) {
  14. Properties props = System.getProperties();
  15. integerCacheHighPropValue =
  16. (String)props.remove("java.lang.Integer.IntegerCache.high");
  17. if (integerCacheHighPropValue != null)
  18. System.setProperties(props);  // remove from system props
  19. }
  20. }
  21. private static class IntegerCache {
  22. static final int high;
  23. static final Integer cache[];
  24. static {
  25. final int low = -128;
  26. // high value may be configured by property
  27. int h = 127;
  28. if (integerCacheHighPropValue != null) {
  29. // Use Long.decode here to avoid invoking methods that
  30. // require Integer‘s autoboxing cache to be initialized
  31. int i = Long.decode(integerCacheHighPropValue).intValue();
  32. i = Math.max(i, 127);
  33. // Maximum array size is Integer.MAX_VALUE
  34. h = Math.min(i, Integer.MAX_VALUE - -low);
  35. }
  36. high = h;
  37. cache = new Integer[(high - low) + 1];
  38. int j = low;
  39. for(int k = 0; k < cache.length; k++) //缓存区间数据
  40. cache[k] = new Integer(j++);
  41. }
  42. private IntegerCache() {}
  43. }
  44. /**
  45. * Returns a <tt>Integer</tt> instance representing the specified
  46. * <tt>int</tt> value.
  47. * If a new <tt>Integer</tt> instance is not required, this method
  48. * should generally be used in preference to the constructor
  49. * {@link #Integer(int)}, as this method is likely to yield
  50. * significantly better space and time performance by caching
  51. * frequently requested values.
  52. *
  53. * @param  i an <code>int</code> value.
  54. * @return a <tt>Integer</tt> instance representing <tt>i</tt>.
  55. * @since  1.5
  56. */
  57. public static Integer valueOf(int i) {
  58. if(i >= -128 && i <= IntegerCache.high)
  59. return IntegerCache.cache[i + 128];
  60. else
  61. return new Integer(i);
  62. }

这儿的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

中间报Unrecognized VM option ‘AutoBoxCacheMax=1000‘错误是因为这个参数只能在HotSpot Server VM上使用,在HotSpot Client VM上不支持。

摘自:http://blog.csdn.net/chengzhezhijian/article/details/9628251

时间: 2024-10-13 19:06:18

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

JAVA Integer值的范围

原文出处:http://hi.baidu.com/eduask%C9%BD%C8%AA/blog/item/227bf4d81c71ebf538012f53.html package com.test; public class Test { public static void main(String []args) { Integer a = 100;//此处若使用new,则==值必为false Integer b = 100; System.out.println(a==b);//true

java Integer类的缓存(转)

首先看一段代码(使用JDK 5),如下: [html] view plain copy public class Hello { public static void main(String[] args) { int a = 1000, b = 1000; System.out.println(a == b); Integer c = 1000, d = 1000; System.out.println(c == d); Integer e = 100, f = 100; System.out

java jdk缓存-128~127的Long与Integer

先判断下下面代码的输出结果 Qa:---------------------------------------------- Long a = Long.valueOf(127); Long b = Long.valueOf(127); System.out.println(a == b); Qb:--------------------------------------------------- Long a = Long.valueOf(128); Long b = Long.value

为什么在 Java 中128==128返回false,而127==127返回true呢?

为什么在 Java 中128==128返回false,而127==127返回true呢? 有这样一段代码 Integer a=127; Integer b=127; System.out.println(a==b); Integer c=128; Integer d=128; System.out.println(c==d); 运行结果为: true false 究竟是为什么呢? 如果两个引用指向相同的对象,它们在 == 表达式中是相等的:如果两个引用指向不同的对象,尽管它们拥有相同的内容即值,

一道 Java 方法传值面试题——Java方法传值的值传递概念和效果 + Integer 缓存机制 + 反射修改 private final 域

原题代码如下: 1 public void test1() { 2 int a = 1, b = 2; 3 System.out.println("before: a=" + a + ", b=" + b); 4 swap1(a, b); 5 System.out.println("after: a=" + a + ", b=" + b); 6 } 7 8 private void swap1(int i1, int i2)

8位有符号的取值范围是-128~+127

这是一个困惑了我几年的问题,它让我对现在的教科书和老师极其不满,从我N年前开始摸电脑时,就几乎在每一本C++教科书上都说,8位有符号的取值范围是-128~+127,为什么不是-127~+127呢,后来的java,int的聚值范围,再32位计算,-2^31 ~ +2^31-1,可是,却从来没有任何一本教科书或一个老师比我解释过这个问题 原因没有在工作上或者是什么地方直接遇到它,所以我也一直忽略它,但心里总是有一根刺.直到刚才!!!! 就是刚才,无聊之极,在看汇编的书时,又遇到它了,但一如以往,书上

byte的取值范围为什么是-128~127

直接给总结:计算机规定了0000 0000 代表0,1000 0000代表的-0没有意义,必须找个~127~127之外的数和它对应,「人为规定-0就是-128」,而且这么做完美适合计算机做减法运算. 来我们一步步分析分析: 1.byte占用8位,每位用0或1表示,能够表示256(2^8)个数据. 2.这8位分为符号位(最高位)和数值位(剩余七位),符号位0表示正数,1表示负数. 3.按上一步的理解,容易得到(+127:0111 1111.+1:0000 0001.+0:0000 0000.-0:

byte的取值范围是-128~127,那么包含-128和127吗?

本帖最后由 王德升老师 于 2019-12-27 17:56 编辑 byte的取值范围为什么是-128~127?如果面试官问你取值范围包含127吗?1. 首先我们知道Java中byte类型是1个字节占8位的.最高位是符号位(正数或者负数),其余7位是数值位.     2. [AppleScript] 纯文本查看 复制代码 ? 1 2 byte b1 = 100; byte b2 = -100; 这里报错吗?不报错!3. [AppleScript] 纯文本查看 复制代码 ? 1 2 3 4 byt

为什么数值类型byte取值范围是(-128~127)?

在解决这个问题之前,我们先了解几个概念? 一.原码, 反码, 补码的概念 正数的反码和补码都与原码一样: 负数的反码.补码与原码不同,负数的反码:原码中除去符号位,其他的数值位取反,0变1,1变0.负数的补码:其反码+1. 做个小Demo,分别写出7和-7的原码.反码.补码.(其中第一位是符号位,0表示正数,1表示负数) Demo 7 -7 原码 00000111 10000111 反码 00000111 11111000 补码 00000111 11111001 一. 机器数和真值 在学习原码