Java 为什么需要包装类,如何使用包装类?
1,767 total views, 3 views today
Java 是号称面向对象的语言,所有的类型都是引用类型。
Object 类是所有类的父类,而且是唯一不用指定明确继承的类。但是基本类型如 int 不是引用类型,也不是继承自 Object,所以 Java 需要一个这样的包装类来使其面向对象的完整性。
包装类同时也可以实现可空类型,即一个数值是空的。Java 集合中也只能放入包装类型,而不支持基本类型。
包装类与自动装箱拆箱
装箱就是 Java 将基本类型转换成对应的包装类型,比如将 int 转换成 Integer 对象。反之将 Integer 转换成 int 值,则称为拆箱。
装箱时,调用 valueOf 方法实现,比如 Integer.valueOf(100);
拆箱时,调用对应的 xxxValue 方法,比如 intValue() 方法。
自动装箱拆箱功能是 java1.5 后才有的。自动装箱拆箱时,由 Java 编译器自动实现转换。
赋值操作的时候,当两边类型不同,就会发生自动装箱拆箱。
自动装箱:
比如:Integer i = 100;
相当于编译器自动作以下的语法编译:
1 2 3 |
Integer i = Integer.valueOf(100); ArrayList intList = new ArrayList(); intList.add(1); //自动装箱 |
自动拆箱:
1 2 3 4 |
Integer i = 10; //装箱 int t = i; //拆箱,实际上执行了 int t = i.intValue(); System.out.println(i++);//拆箱 |
包装类相加时,也会自动拆箱。
1 2 3 4 |
Integer a=new Integer(1); Integer b=new Integer(2); System.out.println(a+b);//自动拆箱 |
自动装箱有性能损耗,在循环中应避免
1 2 3 4 5 |
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;);
包装类的比较
==符号是进行引用的比较。这个比较不会引起自动拆箱。
1 2 3 4 5 6 |
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 的范围内,判等比较的是同一个引用。
1 2 3 4 |
Integer a=127; Integer b=127; System.out.println("a==b : " + (a == b)); //true,是同一个地址引用 |
那么对于 128 这样数字的包装类,判等该怎么做?很简单,手动拆箱,或者用 equals 方法。
1 2 3 4 5 |
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 方法会拆箱后,根据基本类型比较,所以比较的是两者值的大小。
包装类型和基本类型用==比较的时,会发生拆箱
1 2 3 4 5 6 |
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 比较时,会出现问题了。
1 2 3 |
System.out.println("b.equals(c) : " + (b.equals(c))); //true System.out.println("b.equals(d) : " + (b.equals(d))); //false |
发生了什么?看一下 equals 方法源码就知道了
1 2 3 4 5 6 7 |
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/
原创文章,转载请注明出处!http://www.javathings.top/java为什么需要包装类,如何使用包装类/