http://www.cnblogs.com/dolphin0520/p/3780005.html
在Java SE5 之前,如果要生成一个数值为10的Integer对象,必须这样进行:
Integer i = new Integer(10);
而在 从Java SE5开始 就提供了 自动装箱 的特性,如果要生成一个数值为10的Integer对象,只需要这样就可以了:
Integer i = 10;
这个过程中会自动根据数值创建对应的 Integer对象,这就是装箱。
Integer i = 10; //装箱
int n = i; //拆箱
简单一点说:
装箱就是 自动将基本数据类型转换为包装器类型;
拆箱就是 自动将包装器类型转换为基本数据类型。
在装箱的时候自动调用的是 Integer的 valueOf( ) 方法
在拆箱的时候自动调用的是 Integer的 intValue( ) 方法
最关键的下面的面试问题:
public class Main {
public static void main(String[] args) {
Integer i1 = 100;
Integer i2 = 100;
Integer i3 = 200;
Integer i4 = 200;
System.out.println(i1==i2);
System.out.println(i3==i4);
}
}
控制台结果:
true
false
为什么是这个结果呢
看一哈 Integer 的 valueOf( ) 方法的具体实现:
public static Integer valueOf(int i) {
if( i >= -128 && i <= IntegerCache.high )
/* 如果传入的 int 在 [-128,127] 之间,便返回
指向IntegerCache.cache中已经存在的对象的引用 */
return IntegerCache.cache[i + 128];
else
// 否则创建一个新的Integer对象
return new Integer(i);
}
我对这个 自动装箱 过程的理解是 :
在 java 5 之后 ,java的开发者已经 默认准备了 [-128,127] 之间的128*2个 Integer 对象了,
这128*2个对象就像常量一样被调用。
如果传入的数字在此范围内( 比如 i1、i2 ),则返回的都是人家提前备好的128*2个对象的引用
超出此范围的话才会去创建新的对象并返回新对象的引用( 比如 i3、i4 ),
而每个新对象的引用又都是不一样的,才导致了以上结果。
扩展:
Integer、Short、Byte、Character、Long这几个类的valueOf方法的实现是类似的
Double、Float的valueOf方法的实现是类似的
Double类的 valueOf( ) 方***采用与 Integer 类的 valueOf( ) 方法不同的实现。
原因:在某个范围内的整型数值的个数是有限的(128*2),而浮点数却是无限的,没有办法提前准备
至于 Boolean包装类 就更简单了,总共只能有两个值,直接就准备好两个静态final对象就好了:
public static final Boolean TRUE = new Boolean(true);
public static final Boolean FALSE = new Boolean(false);
public static Boolean valueOf(boolean b) {
return (b ? TRUE : FALSE);
}
练习:
(1) '=='比较的是a和b的地址,即比较a和b指向的是否是同一个对象
(2) 对于 ' Integer==int ' 类似的比较,即两个操作数中有一个是(int) 的情况, 比较的是数值是否相等(即Integer类型的那个对象会触发自动拆箱的过程)
public static void main(String[] args) {
Integer a = 1;
Integer b = 2;
Integer c = 3;
Integer d = 3;
Integer e = 321;
Integer f = 321;
Long g = 3L;
Long h = 2L;
System.out.println(c==d);
System.out.println(e==f);
System.out.println(c==(a+b));
System.out.println(c.equals(a+b));
System.out.println(g==(a+b));
System.out.println(g.equals(a+b));
System.out.println(g.equals(a+h));
}
1)c == d 为 true 不用多讲,自动装箱时用的是一个对象
2)e == f 为false 也不多说 , 自动装箱时超出了范围[ -128,127 ],e和f都是新创建的对象,两个对象的地址自然不一样
3)a+b 时会触发自动拆箱操作(为什么? a和b两个都是对象不拆箱怎么进行相加运算?当然要转化成基本数据类型才能+),加完以后变成了 c == (int) ,根据以上(2),c会自动拆箱,即最后比较的是数值
4)c.equals(a+b) 会先触发自动拆箱过程(a+b),再触发自动装箱过程(为什么?相加的结果是作为参数传入c.equals()方法中的,equals()要的当然是Object,当然要装一波箱),也就是说a+b,会先各自调用各自的 intValue() 方法,得到了加法运算后的数值之后,便调用 Integer.valueOf() 方法,再和c进行equals比较
5)同3):用到了(2):a+b之后为int型,Long要触发自动拆箱
6)a+b 的结果自动装箱的时候调用的是Integer.valueOf() 方法,但 g 是用的Long里提前存好的[ -128,127 ]内的对象,而 a+b 用 是Integer里提前存好[ -127,128 ]的对象,连类型都不一样,当然是不同的两个对象
7)a和h 自动拆箱后,运算时 a会自动类型转换成范围更大的 long ,自动装箱时调用的是 Long.valueOf() 方法
运行结果:
true
false
true
true
true
false
true
如果对上面的具体执行过程有疑问,可以尝试获取反编译的字节码内容进行查看:
https://blog.csdn.net/swq463/article/details/84678142
这是代码加反编译的结果:
public static void main(String[] args) {
Integer b = 3; // Method java/lang/Integer.valueOf 自动装箱
Long c = 3L; // Method java/lang/Long.valueOf 自动装箱
System.out.println(c.equals(a)); // Method java/lang/Integer.valueOf a先自动装箱
// Method java/lang/Long.equals
}