java自动装箱的小陷阱

今天学习《深入理解JAVA虚拟机》时,遇见一段关于自动装箱的代码,涉及到了一些自动装箱中比较隐蔽的陷阱,因此记录下来,方便理解。

代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public static void (String[] args) {
Integer a = 1;
Integer b = 2;
Integer c = 3;
Integer d = 3;
Integer e = 321;
Integer f = 321;
Long g = 3L;
System.out.println(c == d);
System.out.println(e == f);
System.out.println(c == (a + b));
System.out.println(c.equals(a + b));
System.out.println(g == (a + b));
System.out.println(g.equals(a + b));
}

代码在虚拟机中运行之后的输出是:true,false,true,true,true,false;

要想正确理解这段代码,我们首先需要明白一条规则:

java中的包装类之间的 “==” 运算在不遇见算术运算的情况下是不会自动拆箱的;

我们先看一下Integer类的源码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public static Integer valueOf(int i) {
return i >= 128 || i < -128 ? new Integer(i) : SMALL_VALUES[i + 128];
}


* A cache of instances used by {@link Integer#valueOf(int)} and auto-boxing
*/
private static final Integer[] SMALL_VALUES = new Integer[256];

static {
for (int i = -128; i < 128; i++) {
SMALL_VALUES[i + 128] = new Integer(i);
}
}

Integer类中存在一个数组,存放了[-128,127]之间的Integer对象,用以缓存,如果整数的值在这个范围之中,则返回预定义的Integer对象;否则,返回新建的对象。

下面逐个解释原因:

  • 第一条中,比较俩个Integer对象是否相等,这俩个Integer对象值都为3,返回的都是预定义的Integer3,是同一个对象,因此==操作返回true;
  • 第二条中,因为321不在缓存范围之中,e 与 f 不是同一个对象,因此==操作返回false;
  • 第三条中,Integer对象遇见+号时会自动拆箱,因此a+b返回的是int型3;在Integerint之间比较==会将Integer拆箱,因此比较的是俩个int,所以应该为true;
  • 第四条中,俩个Integer比较equals()会比较值,因此也应该为true;
  • 第五条同第三条,最后longint进行比较,会将int转为long再比较,应该为true;
  • 第六条中,a+b结果为int型3;当作为equals()方法的参数时,会自动装箱成为Integer对象,而gLong类型,所以应该为false;

我查阅了一下,发现在Integer,Long中都预定义了[-128,127]数值对应的包装对象,如果对象值在范围之内,则会返回预定义的对象。