int
、long
等基本数据类型值比较可以直接使用 ==
比较,其包装类型:Integer
、Long
如果直接使用 ==
比较大小我们会发现一个神奇的现象。当然,阿里规约也对此做出强制规定:
【强制】 所有的相同类型的包装类对象之间值的比较,全部使用
equals
方法比较。
1Integer integer1 = 3;
2Integer integer2 = 3;
3if (integer1 == integer2)
4 System.out.println("integer1 == integer2");
5else
6 System.out.println("integer1 != integer2");
7
8Integer integer3 = 300;
9Integer integer4 = 300;
10if (integer3 == integer4)
11 System.out.println("integer3 == integer4");
12else
13 System.out.println("integer3 != integer4");
14
15Integer integer5 = new Integer(3);
16Integer integer6 = new Integer(3);
17if (integer5 == integer6)
18 System.out.println("integer5 == integer6");
19else
20 System.out.println("integer5 != integer6");
21
22// 输出结果:
23// integer1 == integer2
24// integer3 != integer4
25// integer5 != integer6
这是一个很神奇的结果,特别是对于第一二组对照,几乎相同的代码,只是值的变化却有不同的结果。
对于第一二组的写法,编译器会自动装箱,即调用 valueOf
方法。理所应当我们要看看 valueOf
代码有什么秘密。
1public static Integer valueOf(int i) {
2 if (i >= IntegerCache.low && i <= IntegerCache.high)
3 return IntegerCache.cache[i + (-IntegerCache.low)];
4 return new Integer(i);
5}
6
7private static class IntegerCache {
8 static final int low = -128;
9 static final int high;
10 static final Integer cache[];
11
12 static {
13 int h = 127;
14 String integerCacheHighPropValue =
15 sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high");
16 if (integerCacheHighPropValue != null) {
17 try {
18 int i = parseInt(integerCacheHighPropValue);
19 i = Math.max(i, 127);
20 // Maximum array size is Integer.MAX_VALUE
21 h = Math.min(i, Integer.MAX_VALUE - (-low) -1);
22 } catch( NumberFormatException nfe) {
23 // If the property cannot be parsed into an int, ignore it.
24 }
25 }
26 high = h;
27
28 cache = new Integer[(high - low) + 1];
29 int j = low;
30 for(int k = 0; k < cache.length; k++)
31 cache[k] = new Integer(j++);
32 assert IntegerCache.high >= 127;
33 }
34
35 private IntegerCache() {}
36}
看到这就能明白为什么第一二对照组的结果差异了:当在 [-128,127]
之间赋值时,会被缓存到 IntegerCache
中,所以两个对象是同一个对象,而在此之外的值则是新生成一个对象,通过 ==
判断自然为 false
。
实际通过进一步阅读代码可以得知,所有整数类型的包装类都有类似的缓存机制:
Byte
- ByteCache
Short
- ShortCache
Long
- LongCache
Character
- CharacterCache
为了避免这种诡异情况发生,我们遵循对象的比较方式,对于包装类的值比较用 equals
方法即可。我们可以通过 equals
源码来确认一下结论的正确性:
1public boolean equals(Object obj) {
2 if (obj instanceof Integer) {
3 return value == ((Integer)obj).intValue();
4 }
5 return false;
6}
7
8public int intValue() {
9 return value;
10}
可见 equals
是通过调用 intValue
拆箱得到基本数据类型然后比较的,可以保证值比较的正确性。
当然除了阿里规约推荐的 equals
以外,也可以通过包装类型的比较大小方法 compareTo
去比较:
1public int compareTo(Integer anotherInteger) {
2 return compare(this.value, anotherInteger.value);
3}
4
5public static int compare(int x, int y) {
6 return (x < y) ? -1 : ((x == y) ? 0 : 1);
7}
compareTo
直接取值进行两者比较,根据大小分别返回 -1、0 和 1。