java针对每一种基本数据类型都提供了对应的包装类型,真正实现了面向对象这一概念。
有关资料显示为九种基本数据类型:char、byte、short、int、long、double、boolean、void
对应的包装类型为:Character、Byte、Short、Integer、Long、Double、Boolean、Void
以Integer为例详细了解一下java中的自动装箱、拆箱以及包装类型使用的缓存机制。
java中的装箱是把基本数据类型的值转换为对应包装类型。拆箱刚好相反。
看以下示例:
Integer n1 = 100; Integer n2 = 100; System.out.println(n1 == n2);//true System.out.println(n1.equals(n2));//true Integer n3 = 200; Integer n4 = 200; System.out.println(n3 == n4);//false System.out.println(n3.equals(n4));//true Integer n5 = new Integer(100); Integer n6 = new Integer(100); System.out.println(n5 == n6);//false System.out.println(n5.equals(n6));//true
豫判一下输出的结果会是什么?先豫判一下然后动手运行一下看结果如你所料还是预料之外?
好吧,先回顾一下==与equals的区别。
对于基本类型:==比较的是基本类型的值。
对于引用类型(个人习惯)或者对象:==比较的是对象的引用所存的地址。equals比较的是对象中的值。
接着继续上面的代码:
对象的equals方法返回true这是在预料之中,暂不解释。
为什么n1==n2返回true;n3==n4返回false;n5==n6返回false;
查看源码会发现Integer在自动装箱时调用的是Integer.valueOf()方法,拆箱时调用的是intValue方法
public static Integer valueOf(int i) { final int offset = 128; if (i >= -128 && i <= 127) { // must cache return IntegerCache.cache[i + offset]; } return new Integer(i); }
该方法会先判断i的范围在[-128,+127]之间的会直接返回IntegerCache.cache[];继续看它是什么
static final Integer cache[] = new Integer[-(-128) + 127 + 1]; static { for(int i = 0; i < cache.length; i++) cache[i] = new Integer(i - 128); }
这是Integer的静态内部类IntegerCache,也就是Integer的缓存机制。在第一次调用时会创建一个cache数组,在静态快中使用for循环将-128到+127放入数组中
那么,当i的值在[-128,127]范围内时,系统会去缓存数组中取并返回它的引用。这样做的好处是节省内存、提高性能.为什么是[-128,127]呢?因为这个范围的整数值是使用最广泛的。
到此明了:n1、n2在[-128,127]范围内所以返回的缓存数组中的数据,他们持有的是同一个对象的引用所以调用他们的equals方法返回true;
n3、n4没有在[-128,127]范围内,系统会调用return new Integer(i); 也就使用Integer的构造方法创建Integer对象,而使用这种方法时没有使用缓存所以
equals方法返回false;n5、n6是代码显示的直接使用new Integer(100),与n3、n4一样。
java针对所有的包装类型都使用了缓存策略,感兴趣的可以自己看下,这里不一一详细介绍。