Java 是号称面向对象的语言,所有的类型都是引用类型。 Object 类是所有类的父类,而且是唯一不用指定明确继承的类。但是基本类型如 int 不是引用类型,也不是继承自 Object,所以 Java 需要一个这样的包装类来使其面向对象的完整性。 包装类同时也可以实现可空类型,即一个数值是空的。Java 集合中也只能放入包装类型,而不支持基本类型。
装箱就是 Java 将基本类型转换成对应的包装类型,比如将 int 转换成 Integer 对象。反之将 Integer 转换成 int 值,则称为拆箱。
装箱时,调用 valueOf 方法实现,比如 Integer.valueOf(100);
拆箱时,调用对应的 xxxValue 方法,比如 intValue() 方法。
自动装箱拆箱功能是 java1.5 后才有的。自动装箱拆箱时,由 Java 编译器自动实现转换。
赋值操作的时候,当两边类型不同,就会发生自动装箱拆箱。
自动装箱:
比如:Integer i = 100;
相当于编译器自动作以下的语法编译:
Integer i = Integer.valueOf(100);
ArrayList intList = new ArrayList();
intList.add(1); //自动装箱
自动拆箱:
Integer i = 10; //装箱
int t = i; //拆箱,实际上执行了 int t = i.intValue();
System.out.println(i++);//拆箱
包装类相加时,也会自动拆箱。
Integer a=new Integer(1);
Integer b=new Integer(2);
System.out.println(a+b);//自动拆箱
Integer sum = 0;
for(int i=0; i<100; i++){
sum+=i;
}
上面的代码 sum+=i
可以看成 sum = sum + i
,但是这个操作会把 sum 先拆箱,然后相加后再装箱。等价于下面的代码:
Integer sum = new Integer(sum.intValue() + i;);
==符号是进行引用的比较。这个比较不会引起自动拆箱。
Integer a=128;
Integer b=128;
System.out.println("a==b : " + (a == b)); //false,不会自动拆箱,比较的是引用,不是同一个地址引用
System.out.println("a>b : " + (a > b)); // false,会自动拆箱
System.out.println("a<b : " + (a < b)); // false,会自动拆箱
但是,由于 JVM 会缓存-128 到 127 的 Integer 对象,所以当包装类的值在-128 到 127 的范围内,判等比较的是同一个引用。
Integer a=127;
Integer b=127;
System.out.println("a==b : " + (a == b)); //true,是同一个地址引用
那么对于 128 这样数字的包装类,判等该怎么做?很简单,手动拆箱,或者用 equals 方法。
Integer a=128;
Integer b=128;
System.out.println("a.intValue()==b.intValue() : " + (a.intValue()==b.intValue())); //手动拆箱,true
System.out.println("a.equals(b) : " + (a.equals(b))); //true
equals 方法会拆箱后,根据基本类型比较,所以比较的是两者值的大小。
Integer b=128;
int c=128;
long d=128;
System.out.println("b==c : " + (b == c)); //true ,b自动拆箱
System.out.println("b==d : " + (b == d));//true b自动拆箱,并且会自动提升类型
当包装类和基本类型用 equals 比较时,会出现问题了。
System.out.println("b.equals(c) : " + (b.equals(c))); //true
System.out.println("b.equals(d) : " + (b.equals(d))); //false
发生了什么?看一下 equals 方法源码就知道了
public boolean equals(Object obj) {
if (obj instanceof Integer) {
return value == ((Integer)obj).intValue();
}
return false;
}
基本类型会被自动装箱,放入 equals 方法,然后第一步会判等是否是 Integer 的类型,那么 long d 会被装箱成 Long,所以类型就不一致,直接不进行比较,返回 false。而 int c 会装箱成 Integer 而类型一致,可以继续比较下去。
包装类是一个对象,基本类型不是。 包装类和基本类型可以互相转换,转换的过程称之为装箱拆箱,可以手动转换,也可自动转换。 包装类比较大小的时候有很多坑,比如: ==比较引用,Integer 类型只有在-128 到 127 的范围内,才会持有同一个引用。 equals 方法会先比较类型是否一致,不一致直接 false。 最佳的操作实践是,比较大小的时候,统一先手动拆箱,然后再比较值。
http://coderevisited.com/boxing-and-unboxing-in-java/