JDK1.5以前,建立Integer对象是须要这么写的 Integer i = new Integer("3");java
JDK1.5以后,有了自动装箱,建立Integer对象时,咱们能够这样写 Integer i = 5;编程
1 int num = 3; 2 num = num + 4;
3 //这样写在JDK1.5中是没有问题的 4 Integer x = 3; 5 x = x + 4;
这样以来Integer就拥有了和 int 基本类型同样的能力。表面看起来对象变的能够直接进行运算,这对编程来讲方便了不少。数组
由 Integer x = new Integer(3); 简化成:Integer i = 3; 能够理解为java自动帮咱们作了 x = new Integer(3)的操做。缓存
x = x + 4; 对象是不能直接用来进行运算的,因此java会自动的作拆箱的操做,把(x+4)中的 x 自动拆箱(也就是调用Integer的intValue()方法,把x转换为int类型进行运算),当运算完成以后会把运算结果再次使用装箱赋值给 x 。【整个表达式先拆箱运算完成以后再装箱】ide
1 Integer a = new Integer(127); 2 Integer b = new Integer(127); 3 System.out.println(a==b);//false 4 System.out.println(a.equals(b));//true 5 6 Integer c = 127;//JDK1.5之后,自动装箱若是装箱的是一个字节那么该数据会被共享 不会从新开辟空间 7 Integer d = 127; 8 System.out.println(c==d);//true 9 System.out.println(c.equals(d));//true
经过测试上面代码的测试结果看出,JDK1.5之后Integer自动装箱的数据若是是一个字节,那么该数据会被共享,不会从新开辟新的空间。性能
这就与咱们上面说的装箱拆箱操做相矛盾了,若是Integer x = 3 真的代替了 Integer x = new Integer(3); 这里已经使用了new,怎么可能会不开辟新的空间呢?测试
若是不开辟空间的话,那么共享数据总要存在于一块共享空间以内,难道会像字符串那样维护了一个常量池?ui
1 /** 2 * Cache to support the object identity semantics of autoboxing for values between 3 * -128 and 127 (inclusive) as required by JLS. 4 * 5 * The cache is initialized on first usage. The size of the cache 6 * may be controlled by the -XX:AutoBoxCacheMax=<size> option. 7 * During VM initialization, java.lang.Integer.IntegerCache.high property 8 * may be set and saved in the private system properties in the 9 * sun.misc.VM class. 10 */ 11 12 private static class IntegerCache { 13 static final int low = -128; 14 static final int high; 15 static final Integer cache[]; 16 17 static { 18 // high value may be configured by property 19 int h = 127; 20 String integerCacheHighPropValue = 21 sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high"); 22 if (integerCacheHighPropValue != null) { 23 int i = parseInt(integerCacheHighPropValue); 24 i = Math.max(i, 127); 25 // Maximum array size is Integer.MAX_VALUE 26 h = Math.min(i, Integer.MAX_VALUE - (-low) -1); 27 } 28 high = h; 29 30 cache = new Integer[(high - low) + 1]; 31 int j = low; 32 for(int k = 0; k < cache.length; k++) 33 cache[k] = new Integer(j++); 34 } 35 36 private IntegerCache() {} 37 }
经过查找源码发现,原来Integer类内部维护了一个静态内部类,这是JDK1.5中,为 Integer 的操做引入了一个新的特性,用来节省内存和提升性能。整型对象在内部实现中经过使用相同的对象引用实现了缓存和重用。this
Javadoc 详细的说明这个类是用来实现缓存支持,并支持 -128 到 127 之间的自动装箱过程。最大值 127 能够经过 JVM 的启动参数 -XX:AutoBoxCacheMax=size 修改。 缓存经过一个 for 循环实现。从小到大的建立尽量多的整数并存储在一个名为 cache 的整数数组中。这个缓存会在 Integer 类第一次被使用的时候被初始化出来。之后,就可使用缓存中包含的实例对象,而不是建立一个新的实例(在自动装箱的状况下)。spa
经过查看Integer的构造方法发现,没有一个构造方法会从IntegerCache中取值,很显然自动装箱的操做并非经过new Integer()来完成的。应该是经过其余的方法!
1 /** 2 * Returns an {@code Integer} instance representing the specified 3 * {@code int} value. If a new {@code Integer} instance is not 4 * required, this method should generally be used in preference to 5 * the constructor {@link #Integer(int)}, as this method is likely 6 * to yield significantly better space and time performance by 7 * caching frequently requested values. 8 * 9 * This method will always cache values in the range -128 to 127, 10 * inclusive, and may cache other values outside of this range. 11 * 12 * @param i an {@code int} value. 13 * @return an {@code Integer} instance representing {@code i}. 14 * @since 1.5 15 */ 16 public static Integer valueOf(int i) { 17 assert IntegerCache.high >= 127; 18 if (i >= IntegerCache.low && i <= IntegerCache.high) 19 return IntegerCache.cache[i + (-IntegerCache.low)]; 20 return new Integer(i); 21 }
经过查看源码发现valueOf(int i)【只有这一个方法,其余的重载方法未操做IntegerCache】中出现了对IntegerCache的操做。看源码咱们了解到若是传入的-128<i<127 就会从IntegerCache的cache数组中取出共享数据,若是不在这个范围以内则使用new Integer(i)。
由此也就完全明白了装箱拆箱的内幕!
> 装箱使用的是valueOf(int i)
> 拆箱使用的是intValue();
其实这种缓存行为不只适用于Integer对象,针对全部整数类型的类都有相似的缓存机制。
有 ByteCache 用于缓存 Byte 对象
有 ShortCache 用于缓存 Short 对象
有 LongCache 用于缓存 Long 对象
有 CharacterCache 用于缓存 Character 对象
Byte、Short、Long有固定范围:-128~127,对于 Character范围是:0~127。
除了Integer能够经过参数改变范围外,其余对象都不能够。