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

Java Integer缓存机制深度解析
这篇博客探讨了Java中Integer对象在-128到127之间的缓存机制,解释了为何在该范围内,相同数值的Integer对象使用`==`比较会返回不同结果。通过JVM参数可以调整缓存范围,影响对象的复用和垃圾回收。

最近在项目中遇到一个问题,两个值相同的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 =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
  1. public class Hello   
  2. {   
  3.   public static void main(String[] args)   
  4.   {   
  5.     int a = 1000b = 1000;   
  6.     System.out.println(a == b);   
  7.   
  8.     Integer c = 1000d = 1000;   
  9.     System.out.println(c == d);   
  10.   
  11.     Integer e = 100f = 100;   
  12.     System.out.println(e == f);   
  13.   }   
  14. }   

输出结果:

[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源码,如下:

[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对象。

再看其它的包装器:

  • Boolean:(全部缓存)
  • Byte:(全部缓存)

  • Character(<= 127缓存)
  • Short(-128 — 127缓存)
  • Long(-128 — 127缓存)

  • Float(没有缓存)
  • Doulbe(没有缓存)

同样对于垃圾回收器来说:

[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上不支持。
<think>首先,用户查询是关于“JavaInteger与int的区别”,并且系统级指令规定必须使用中文回答,以及LaTeX格式。用户提供了几个引用:-引用[1]提到了定义。-引用[2]提到了一些不同点。-引用[3]详细列出了5个区别:数据类型、默认、存储方式、实例化方式、比较方式。-引用[4]提到了内存区别:非new生成的Integer指向常量池,newInteger指向堆。我的回答需要:1.结构清晰,逐步解决问题。2.使用中文。3.在数学表达式中使用$...$或$$...$$(但在此主题下,可能没有太多数学,如果有变量等,需要使用)。4.生成相关问题。5.在引用的段落末尾添加引用标识如[^1]。在这个主题中,涉及到的内容是编程语言的,可能没有复杂的数学公式。但需要小心:如果有变量名如int,在行内提到时应该用$int$。例如,int变量应该写成$int$。结构建议:-开头简要介绍。-列出主要区别,参考引用。-最后生成相关问题。生成相关问题:-根据系统指令,在回答末尾添加相关问题部分。参考用户上一次问题:用户问的是区别,我需要在回答中整合引用的内容。关键区别从引用中提取:1.**数据类型**:int是基本数据类型;Integer是包装类(即包装数据类型)。2.**默认**:int默认是0;Integer默认是null。3.**存储方式**:int直接存储数据Integer存储对象引用。4.**实例化**:int不需要实例化;Integer需要实例化(如newInteger())。5.**比较**:int用==比较Integerequals比较。6.**内存地址**:newInteger()在堆中;非new(如自动装箱)可能指向常量池(-128127)。来自引用[4],关于内存。需要确保回答真实可靠。既然引用提供,我可以基于这些构建回答。回答结构:1.**引言**:解释intInteger的用途基本区别。2.**主要区别**:列出关键点。3.**详细说明**:结合引用解释。4.**例子**:添加一个简单的Java代码示例来演示比较部分。5.**结论**:总结何时使用哪个。6.**相关问题**:生成相关问题。代码部分需要使用markdowncodeblock,如示例中的快速排序代码。末尾添加相关问题部分,用§§相关问题§§标识。确保在引用内容后添加引用标识,例如在段落末尾添加[^1]。现在,思考问题:用户的问题是关于区别,所以回答应全面覆盖。拟定大纲:-**1.数据类型**:int是基本类型;Integer是包装类。引用[^3]-**2.默认**:int为0;Integer为null。引用[^3]-**3.存储方式**:int存储Integer存储引用。引用[^3]-**4.实例化**:int不;Integer是。引用[^3]-**5.比较方式**:int用==Integerequals。并讨论内存问题。引用[^3][^4]-**6.自动装箱拆箱**:解释转换过程(未被引用,但相关)。-**7.常量池**:对于Integer的范围影响。引用[^4]在引用中提到过,所以包含。生成相关问题:类似示例,相关问题应基于主题:1.Integerint在性能上有何区别?2.Java中自动装箱是如何工作的?3.如何处理Integerint的null问题?等。现在,编写回答。</think> 以下是针对Java中`int``Integer`区别的详细解释。我将从基础概念逐步展开,结合关键区别点进行说明。需要注意的是: - `int`是Java的基本数据类型(primitive type),直接存储整数数- `Integer`是Java的包装类(wrapper class),属于对象类型,它将`int`封装为对象,提供额外方法(如`equals()`, `parseInt()`等)。 主要区别源自它们的类型底层实现,我参考了提供的引用内容[^1][^2][^3][^4],并在相关段落末尾添加了引用标识。 ### 1. **数据类型不同** - `int` 是基本数据类型,直接在内存中存储整数(例如,`int a = 10;`)。 - `Integer` 是包装类,属于对象类型(即`java.lang.Integer`),需要实例化创建对象(例如,`Integer b = new Integer(10);`)。因此,`Integer`支持面向对象特性,如方法调用继承。 [^3] ### 2. **默认不同** - `int` 的默认是0(在类成员变量或静态变量中初始化时)。 - `Integer` 的默认是`null`,因为它是一个对象类型,未实例化时为`null`。这可能导致`NullPointerException`异常如果在使用前不检查。 [^3] ### 3. **内存存储方式不同** - `int` 直接在栈内存中存储数(例如,变量`int i = 5;`在内存中就是一个整数5)。 - `Integer` 存储在堆内存中,实际存储的是对象的引用。例如: - 对于`Integer a = new Integer(5);`,生成一个新对象在堆中。 - 对于`Integer a = 5;`(自动装箱),Java可能使用常量池优化:若-128127范围内,会复用已有对象,否则创建新对象。这可能导致内存地址不同。 [^3][^4] ### 4. **实例化方式不同** - `int` 不需要实例化,声明后可直接赋(例如,`int i = 10;`)。 - `Integer` 需要实例化才能使用(例如,通过`new Integer(10)`或自动装箱`Integer j = 10;`)。这会影响代码灵活性对象管理。 [^3] ### 5. **比较方式不同** - `int` 使用`==`运算符比较(例如,`int a = 10; int b = 10; a == b` 返回`true`,因为比较)。 - `Integer` 必须使用`equals()`方法比较,否则`==`会检查对象引用是否相同: - `Integer a = new Integer(10); Integer b = new Integer(10);`,则`a == b`为`false`(引用不同)。 - `Integer a = 10; Integer b = 10;`,则`a == b`为`true`(相同且在常量池范围内)。 - 最佳实践:总是使用`a.equals(b)`避免错误。 [^3][^4] ### 6. **自动装箱拆箱** 在实际使用中,Java提供自动装箱(autoboxing)拆箱(unboxing)机制: - 自动装箱:`Integer c = 10;` 隐含地转换为`Integer.valueOf(10)`。 - 自动拆箱:`int d = c;` 隐含地转换为`c.intValue()`。 这种方式简化了代码,但在高频率操作中可能影响性能(如循环中多次装箱/拆箱会生成临时对象)。 这体现了面向对象基本类型的桥梁作用[^1][^2]。 ### 示例代码演示比较 ```java public class Main { public static void main(String[] args) { int a = 100; int b = 100; System.out.println(a == b); // true, 比较 Integer c = new Integer(100); Integer d = new Integer(100); System.out.println(c == d); // false, 比较引用 System.out.println(c.equals(d)); // true, 比较 Integer e = 100; // 自动装箱,使用常量池 Integer f = 100; System.out.println(e == f); // true (范围内) Integer g = 200; // 超出范围,新建对象 Integer h = 200; System.out.println(g == h); // false (范围外) } } ``` ### 总结 - **使用场景**: - 用`int`时优先:内存效率高、适用于数计算(如计数器或循环变量)。 - 用`Integer`时适用:需要null处理、需要对象方法(如集合操作`List<Integer>`)或涉及对象比较- 核心区别在于`int`是基础类型直接处理,而`Integer`是对象处理引用Java的自动装箱机制帮助简化代码,但需注意潜在null性能问题[^3][^4]。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值