用==比较2个Integer对象时,有些小细节需要注意的。Integer,Short,Long和String都是常量类,用final修饰class,声明时可以直接赋值,也可以new,他们之间有什么区别呢?关于String,可以看我的另一篇博文http://blog.youkuaiyun.com/dream_broken/article/details/8759616 ,在这就不多说了。下面就拿Integer说说,Short,Long都是差不多的(Double不是).
好了,先直接上源码。
public class TestInt {
public static void main(String[] args){
Integer c=100,d=100;
Integer e=1000,f=1000;
Integer g=new Integer(100);
Integer h=new Integer(100);
Integer j =new Integer(1000);
Integer k =new Integer(1000);
System.out.println(c==d);
System.out.println(e==f);
System.out.println(g==h);
System.out.println(j==k);
System.out.println(e==j);
}
} 如果你都对了,并且知道理由,那你可以关闭该网页了。
运行结果:
true false false false false
我做的时候,错了e==f的判断。其它的使用了new的,相信大家也不会错,因为==比较的是引用值,而使用了new说明在堆(Eden区)创建一个新对象。那么为什么c==d成立,而e==f不成立呢。
我第一件事就是用javap -verbose查看class文件。
public static void main(java.lang.String[]);
Code:
Stack=3, Locals=9, Args_size=1
0: bipush 100
2: invokestatic #16; //Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
5: astore_1
6: bipush 100
8: invokestatic #16; //Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
11: astore_2
12: sipush 1000
15: invokestatic #16; //Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
18: astore_3
19: sipush 1000
22: invokestatic #16; //Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
25: astore 4
27: new #17; //class java/lang/Integer
30: dup
31: bipush 100
33: invokespecial #22; //Method java/lang/Integer."<init>":(I)V
36: astore 5
38: new #17; //class java/lang/Integer
41: dup
42: bipush 100
44: invokespecial #22; //Method java/lang/Integer."<init>":(I)V
47: astore 6
49: new #17; //class java/lang/Integer
52: dup
53: sipush 1000
56: invokespecial #22; //Method java/lang/Integer."<init>":(I)V
59: astore 7
61: new #17; //class java/lang/Integer
64: dup
65: sipush 1000
68: invokespecial #22; //Method java/lang/Integer."<init>":(I)V
71: astore 8
73: getstatic #25; //Field java/lang/System.out:Ljava/io/PrintStream;
76: aload_1
77: aload_2 发现:对于Integer x=500这形式的声明并赋值,都调用了Integer类中的静态方法Integer.valueOf(int i);对于Integer x=new Integer(500)这形式的,直接调用构造器.
再把class文件反编译看看源码。
public class TestInt
{
public static void main(String[] args)
{
Integer c = Integer.valueOf(100); Integer d = Integer.valueOf(100);
Integer e = Integer.valueOf(1000); Integer f = Integer.valueOf(1000);
Integer g = new Integer(100);
Integer h = new Integer(100);
Integer j = new Integer(1000);
Integer k = new Integer(1000);
System.out.println(c == d);
System.out.println(e == f);
System.out.println(g == h);
System.out.println(j == k);
System.out.println(e == j);
}
} 到了这,非常明白了,原来是编译器做了处理。那么对于c==d成立,e==f不成立的原因应该就在Integer.valueOf(int i)这个方法里面了。好,继续跟踪,看看Integer.valueOf(int i)做了什么见不得人的事.
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);
} 看到这源码,相信大家都OK了,如果-128<=i<=127就从IntegerCache.cache[]数组中获得Integer对象,如果不是就直接new,那么再看看IntegerCache.cache[]数组是什么。继续追踪.......
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);
}
} 追踪到这,终于松了口气了,原来加载IntegerCache类是就初始化了Integer类型的cache[]数组,并将数值位于-128到127之间的Integer对象保存到数组中。如果Integer.valueOf(int i)中的i如果位于该范围,就直接把数组内对应的对象引用值返回,所以Integer c=100,d=100;c==d是成立的,因为他们都指向同一个对象,而对于Integer e=1000,f=1000;e==f不成立,因为他们都不在范围内,直接new了。 对于Short,Long都是一样,Double就不一样了,呵呵,大家可以查看源码,这样更清晰原因。