一、装箱、拆箱定义
如果一个int型量被传递到需要一个Integer对象的地方,那么,编译器将在幕后插入一个对Integer构造方法的调用,这就叫做自动装箱。而如果一个Integer对象被放到需要int型量的地方,则编译器将幕后插入一个队intValue方法的调用,这就叫做自动拆箱。
public static void main(String[] args) { // 装箱 Integer i1 = Integer.valueOf(1); // 自动装箱 Integer i2 = 1;// 默认执行valueOf(1); System.out.println(i1 == i2);// true // 自动拆箱 int i3 = i1.intValue(); int i4 = i2.intValue(); System.out.println(i3 == i4);// true // 超出Integer的缓存范围,不从私有静态内部类IntegerCache的数组cache中获得,通过new返回新对象 Integer i5 = 128; Integer i6 = -129; Integer i5_1 = 128; Integer i6_1 = -129; System.out.println(i5 == i5_1);// false System.out.println(i6 == i6_1);// false }
所以说,对于-127~127之间的值,Integer对象中存在一个IntegerCache的私有静态内部类,这个内部类有一个Integer类型的静态常量数组,在这个内部类中通过静态方法块,初始化了这个静态常量数组。默认这个数组保存[-127,128)之间的Integer对象。源码如下:
1 private static class IntegerCache { 2 static final int low = -128; 3 static final int high; 4 static final Integer cache[]; 5 6 static { 7 // high value may be configured by property 8 int h = 127; 9 String integerCacheHighPropValue = 10 sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high"); 11 if (integerCacheHighPropValue != null) { 12 try { 13 int i = parseInt(integerCacheHighPropValue); 14 i = Math.max(i, 127); 15 // Maximum array size is Integer.MAX_VALUE 16 h = Math.min(i, Integer.MAX_VALUE - (-low) -1); 17 } catch( NumberFormatException nfe) { 18 // If the property cannot be parsed into an int, ignore it. 19 } 20 } 21 high = h; 22 23 cache = new Integer[(high - low) + 1]; 24 int j = low; 25 for(int k = 0; k < cache.length; k++) 26 cache[k] = new Integer(j++); 27 28 // range [-128, 127] must be interned (JLS7 5.1.7) 29 assert IntegerCache.high >= 127; 30 } 31 32 private IntegerCache() {} 33 }
通过下面的源码可以知道,为什么Integer i = 128;与Integer y = 128;,通过==比较的结果为false。如果要赋值的int变量在范围内,则返回数组中的对象给Integer,如果不在,则通过带参构造方法,new一个新的Integer对象。
1 public 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 }
二、其它包装类型
The Java Language Specification, 3rd Edition 写道:
为了节省内存,对于下列包装对象的两个实例,当它们的基本值相同时,他们总是==:
- Boolean :全部缓存
- Byte :全部缓存
- Character : <=127缓存
- Short : (-128,127)缓存
- Long : (-128,127)缓存
- Float : (没有缓存)
- Double : (没有缓存)
其中Character的缓存源码:
1 private static class CharacterCache { 2 private CharacterCache(){} 3 4 static final Character cache[] = new Character[127 + 1]; 5 6 static { 7 for (int i = 0; i < cache.length; i++) 8 cache[i] = new Character((char)i); 9 } 10 }
其中Float没有缓存,直接返回源码:
1 public static Float valueOf(String s) throws NumberFormatException { 2 return new Float(parseFloat(s)); 3 }
三、用处
除了包装类提供了额外的方法外,当使用集合框架时,泛型为Object类型,所以如果声明为List<int> list...,则这样是不行的,必须声明为List<Integer> list...。
四、存储的位置
因为是对象,所以存储在堆中。