文章分类:Java编程
我们首先来看一段代码:
- Integer i=100;
- Integer j=100;
- System.out.println(i==j); //(1)
- Integer i=200;
- Integer j=200;
- System.out.println(i==j); //(2)
Integer i=100;
Integer j=100;
System.out.println(i==j); //(1)
Integer i=200;
Integer j=200;
System.out.println(i==j); //(2)
其中(1) : true , (2) false 。这到底是为什么呢?
我们分两步来说明这个问题:
首先 Integer i=100; 编译器会自动将int类型常数100包装成Interger,采用的是Integer.valueOf(100); 这个方法。
然后我们看看valueOf(int)这个方法的源代码:
- /*
- * 返回一个表示指定的 int 值的 Integer 实例。如果不需要新的 Integer 实例,则
- * 通常应优先使用该方法,而不是构造方法 Integer(int),因为该方法有可能通过
- * 缓存经常请求的值而显著提高空间和时间性能。
- * @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) {
- final int offset = 128;
- if (i >= -128 && i <= 127) { // must cache
- return IntegerCache.cache[i + offset];
- }
- return new Integer(i);
- }
- /*
- * IntegerCache内部类
- * 其中cache[]数组用于存放从-128到127一共256个整数
- */
- private static class IntegerCache {
- private IntegerCache(){}
- static final Integer cache[] = new Integer[-(-128) + 127 + 1];
- static {
- for(int i = 0; i < cache.length; i++)
- cache[i] = new Integer(i - 128);
- }
- }
/*
* 返回一个表示指定的 int 值的 Integer 实例。如果不需要新的 Integer 实例,则
* 通常应优先使用该方法,而不是构造方法 Integer(int),因为该方法有可能通过
* 缓存经常请求的值而显著提高空间和时间性能。
* @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) {
final int offset = 128;
if (i >= -128 && i <= 127) { // must cache
return IntegerCache.cache[i + offset];
}
return new Integer(i);
}
/*
* IntegerCache内部类
* 其中cache[]数组用于存放从-128到127一共256个整数
*/
private static class IntegerCache {
private IntegerCache(){}
static final Integer cache[] = new Integer[-(-128) + 127 + 1];
static {
for(int i = 0; i < cache.length; i++)
cache[i] = new Integer(i - 128);
}
}
原来如此,当-128=<i<=127的时候,返回的是IntegerCache中的数组的值;当 i>127 或 i<-128 时,返回的是Integer类对象。
这就好解释:
- Integer i=100;
- Integer j=100;
- System.out.println(i==j); //(1)
Integer i=100;
Integer j=100;
System.out.println(i==j); //(1)
此时的 i=IntegerCache.cache[228],因此 Integer引用i中存储的是cache数组第228号元素的地址。同理j也是同一个cache数组的第228号元素的地址(因为cache是Integer的静态数组,只有一个)。i==j比较的是引用地址,因此相等。
- Integer i=200;
- Integer j=200;
- System.out.println(i==j); //(2)
Integer i=200;
Integer j=200;
System.out.println(i==j); //(2)
此时的 i=new Integer(200); 同样j=new Integer(200) 。两次都在堆中开辟了Integer的对象。i 和 j 中存储的堆得对象地址是完全不同的。i==j 自然不相等了。
那么这样做有什么意义呢? 我们来看看API的解释:
- 返回一个表示指定的 int 值的 Integer 实例。如果不需要新的 Integer 实例,
- 则通常应优先使用该方法,而不是构造方法 Integer(int),因为该方法有可能
- 通过缓存经常请求的值而显著提高空间和时间性能。
返回一个表示指定的 int 值的 Integer 实例。如果不需要新的 Integer 实例,
则通常应优先使用该方法,而不是构造方法 Integer(int),因为该方法有可能
通过缓存经常请求的值而显著提高空间和时间性能。
加入我们在编程时大量需要值为100的Integer对象,如果只能通过new来创建的话。是不是需要在堆中开辟大量值一样的Integer对象呢!这是相当不划算的。既然如此,Java中的常量池的想法是不是可以提醒我们点什么呢。是的,IntegerCache.cache就相当于这样一个常量池。当我们需要Integer i=100的时候,直接从cache中取出第[100+128]号元素的地址赋值引用i,再次需要Integer j=100时,还是直接去这个地址赋给j ..... 是不是省去了再堆中不停的创建对象的代价了(空间,时间上的消耗都很大)。
http://hxraid.javaeye.com/blog/614440