## 问题描述

### 例一

``````public static void main(String[] args) {
for (int i = 0; i < 150; i++) {
Integer a = i;
Integer b = i;
System.out.println(i + " " + (a == b));
}
}``````

`i`取值从0到150，每次循环`a``b`的数值均相等，输出`a == b`。运行结果：

``````0 true
1 true
2 true
3 true
...
126 true
127 true
128 false
129 false
130 false
...``````

### 例二

``````public static void main(String[] args) {
Map<Integer, Integer> mapA = new HashMap<>();
Map<Integer, Integer> mapB = new HashMap<>();
for (int i = 0; i < 150; i++) {
mapA.put(i, i);
mapB.put(i, i);
}
for (int i = 0; i < 150; i++) {
System.out.println(i + " " + (mapA.get(i) == mapB.get(i)));
}
}``````

`i`取值从0到150，`mapA``mapB`均存储`(i, i)`数值对，输出`mapA`的值与`mapB`的值的比较结果。运行结果：

``````0 true
1 true
2 true
3 true
...
126 true
127 true
128 false
129 false
130 false
...``````

## 原因分析

### 自动装箱

``Integer a = 1;``

``Integer a = Integer.valueOf(1);``

`valueOf()`方法返回一个Integer类型值，并将其赋值给变量`a`。这就是int的自动装箱。

### 是同一个对象吗？

``````public static void main(String[] args) {
for (int i = 0; i < 150; i++) {
Integer a = i;
Integer b = i;
System.out.println(i + " " + (a == b));
}
}``````

``new Integer(1) == new Integer(1);``

``````for(int i=0;i<150;i++){
Integer a=i;
Integer b=i;
System.out.println(a+" "+b+" "+System.identityHashCode(a)+" "+System.identityHashCode(b));
}``````

`identityHashCode()`方法可以理解为输出对应变量的内存地址，输出为：

``````0 0 762119098 762119098
1 1 1278349992 1278349992
2 2 1801910956 1801910956
3 3 1468253089 1468253089
...
126 126 1605164995 1605164995
127 127 1318497351 1318497351
128 128 101224864 479240824
129 129 1373088356 636728630
130 130 587071409 1369296745
...``````

### 看看源码

“从0到127不同时候自动装箱得到的是同一个对象”就只能有一种解释：自动装箱并不一定new出新的对象。

``````/**
* Returns an {@code Integer} instance representing the specified
* {@code int} value.  If a new {@code Integer} instance is not
* required, this method should generally be used in preference to
* the constructor {@link #Integer(int)}, as this method is likely
* to yield significantly better space and time performance by
* caching frequently requested values.
*
* This method will always cache values in the range -128 to 127,
* inclusive, and may cache other values outside of this range.
*
* @param  i an {@code int} value.
* @return an {@code Integer} instance representing {@code i}.
* @since  1.5
*/
public static Integer valueOf(int i) {
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
}``````

``````private static class IntegerCache {
static final int low = -128;
static final int high;
static final Integer cache[];

static {
// high value may be configured by property
int h = 127;
String integerCacheHighPropValue =
sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high");
if (integerCacheHighPropValue != null) {
try {
int i = parseInt(integerCacheHighPropValue);
i = Math.max(i, 127);
// Maximum array size is Integer.MAX_VALUE
h = Math.min(i, Integer.MAX_VALUE - (-low) -1);
} catch( NumberFormatException nfe) {
// If the property cannot be parsed into an int, ignore it.
}
}
high = h;

cache = new Integer[(high - low) + 1];
int j = low;
for(int k = 0; k < cache.length; k++)
cache[k] = new Integer(j++);

// range [-128, 127] must be interned (JLS7 5.1.7)
assert IntegerCache.high >= 127;
}

private IntegerCache() {}
}``````

## 解决方法

``````for (int i = 0; i < 150; i++) {
Integer a = i;
Integer b = i;
System.out.println(i + " " + (a.equals(b)));
}``````

## 备注

byteByte-128 ~ 127-128 ~ 127
shortShort-2^15 ~ (2^15 - 1)-128 ~ 127
intInteger-2^31 ~ (2^31 - 1)-128 ~ 127
longLong-2^63 ~ (2^63 - 1)-128～127
floatFloat----
doubleDouble----
booleanBooleantrue, falsetrue, false
charCharacter\u0000 ~ \uffff\u0000 ~ \u007f