我们知道,所有对象型的数据类型的基类是java.lang.Object。而写java程序的时候非常多的工作都是在写这些类,和实现里面的方法。而偏偏就有那么8种基本类型和
他们不一样。以至于让你来回在这两种之间转换,只是很让人头疼的事情。Java中的int , long , char这样的类型不是对象型。因此,java里提供了一种叫做包装类(wrapper)的东西,是基本类型,有着相应的对象类型Integer , Long , Character等。表1列出了java API中的包装器类:
基本类型 包装器类
构造函数变元
boolean Boolean boolean或String
byte Byte byte或String
char Character char
double Double double或String
float Float float、double或String
int Integer int或String
long Long long或String
short Short short或String
Java中的包装器类有两个主要的目的:
1.提供一种机制,将基本值“包装”到对象中,从而使基本值能够包含在为对象而保留的操作中,比如添加到Collections 中,或者从带对象返回值的方法中返回。注意,java5增加了自动装箱和拆箱,
程序员过去需手工执行的许多包装操作,现在可以由java自动处理了。
2.为基本值提供分类功能。这些功能大多数于各种转换有关:在基本值和String 对象间相互转换,在基本值和String 对象之间按不同基数转换,如二进制、八进制和十六进制。
基本数据(Primitive)类型的自动装箱(autoboxing)、拆箱(unboxing)是自J2SE 5.0开始提供的功能。虽然为您打包基本数据类型提供了方便,但提供方便的同时表示隐藏了细节,建议在能够区分基本数据类型与对象的差别时再使用。
看下面的
例子:
public class Test1 {
public static void main(String[] args) {
//装箱
int i = 0;
Integer integer = i;//i这么一个基本类型的数,可以赋值给Integer型的变量
//简单的拆箱
int j = integer;//integer这种包装类型的数,也能赋值给j这个原始类型的变量
Integer counter = 1; //装箱
int counter2 = counter; //拆箱
while (counter < 100) {
System.out.println("计数 "+counter++); //看啊,counter这个对象型的数,还能自动增加
}
}
}
在幕后
JVM已经自动执行了转换,同理Boolean和boolean之间也可以,自动拆箱装箱。但是,Integer和int毕竟还是有着不同的。
java 自动装箱与拆箱 中的
陷阱
自动装箱与拆箱的功能事实上是编译器来帮您的忙,编译器在编译时期依您所编写的语法,决定是否进行装箱或拆箱动作。例如:
Integer i = 100;相当于编译器自动为您作以下的语法编译:
Integer i = new Integer(100);所以自动装箱与拆箱的功能是所谓的“编译器蜜糖”(Compiler Sugar),虽然使用这个功能很方便,但在程序运行阶段您得了解Java的语义。例如下面的程序是可以通过编译的:
Integer i = null;int j = i;这样的语法在编译时期是合法的,但是在运行时期会有
错误,因为这种写法相当于:
Integer i = null;int j = i.intValue();null表示i没有参考至任何的对象实体,它可以合法地指定给对象参考名称。由于实际上i并没有参考至任何的对象,所以也就不可能操作intValue()方法,这样上面的写法在运行时会出现NullPointerException错误。
自动装箱、拆箱的功能提供了方便性,但隐藏了一些细节,所以必须小心。再来看范例4.6,您认为结果是什么呢?
ü 范例4.6 AutoBoxDemo2.java
public class AutoBoxDemo2 {
public static void main(String[] args) {
Integer i1 = 100;
Integer i2 = 100;
if (i1 == i2)
System.out.println("i1 == i2");
else
System.out.println("i1 != i2");
}
}
从自动装箱与拆箱的机制来看,可能会觉得结果是显示i1 == i2,您是对的。那么范例4.7的这个程序,您觉得结果是什么?
ü 范例4.7 AutoBoxDemo3.java
public class AutoBoxDemo3 {
public static void main(String[] args) {
Integer i1 = 200;
Integer i2 = 200;
if (i1 == i2)
System.out.println("i1 == i2");
else
System.out.println("i1 != i2");
}
}
结果是显示i1 != i2,这有些令人惊讶,两个范例语法完全一样,只不过改个数值而已,结果却相反。
其实这与==运算符的比较有关,在第3章中介绍过==是用来比较两个基本数据类型的变量值是否相等,事实上==也用于判断两个对象引用名称是否参考至同一个对象。
在自动装箱时对于值从–128到127之间的值,它们被装箱为Integer对象后,会存在
内存中被重用,所以范例4.6中使用==进行比较时,i1 与 i2实际上参考至同一个对象。如果超过了从–128到127之间的值,被装箱后的Integer对象并不会被重用,即相当于每次装箱时都新建一个Integer对象,所以范例4.7使用==进行比较时,i1与i2参考的是不同的对象。
所以不要过分依赖自动装箱与拆箱,您还是必须知道基本数据类型与对象的差异。范例4.7最好还是依正规的方式来写,而不是依赖编译器蜜糖(Compiler Sugar)。例如范例4.7必须改写为范例4.8才是正确的。
ü 范例4.8 AutoBoxDemo4.java
public class AutoBoxDemo4 {
public static void main(String[] args) {
Integer i1 = 200;
Integer i2 = 200;
if (i1.equals(i2))
System.out.println("i1 == i2");
else
System.out.println("i1 != i2");
}
}
结果这次是显示i1 == i2。使用这样的写法,相信也会比较放心一些,对于这些方便但隐藏细节的功能到底
要不要用呢?基本上只有一个原则:如果您不确定就不要用。
包装器对象的几种最常见方法:
1. 构造函数
除了Character类之外,所有包装器类都提供两个构造函数:一个以要构建的基本类型作为变元,另一个以要构建类型的String表示作为变元。例如:
Integer i1 = new Integer(42);
Integer i2 = new Integer(“42”);
Character类只有一个构造函数,它以一个字符作为变元。例如:
Character c1 = new Character(‘c’);
2. valueOf()方法
多数包装器类都提供两个静态valueOf()方法,从而使我们能用另一种方法来创建包装器类对象。这两种方法都以适合基本类型的String 表示作为第一个变元,第二个方法带一个额外的变元int radix , 它表示第一个变元以什么基数(二进制、八进制或十六进制)。例如:
Integer i2 = Integer. valueOf(“101011”,2);
3. xxxValue()方法
当需要将被包装的数值转换为基本类型时,可使用几个xxxValue()方法之一。这一系列的方法都是无变元方法。一共有36个xxxValue()方法。6种数值包装器类中每一种都有6个方法,因此任何数值包装器都能够转换成任何基本数
值类型。例如:
Integer i2 = new Integer(42);
byte b = i2.byteValue();
short s = i2.shortValue();
double d = i2.doubleValue();
4. parseXxx()和valueOf()方法
6种parseXxx()方法与在所有数值包装器类中存在的valueOf()方法紧密相关。parseXxx()和valueOf()方法都已String作变元,如果String变元形式不正确,则会抛出NumberFormatException(也称NFE)。如果底层基本类型是4种整数类型中的任何一种时,二者都能够以不同的基转换String对象。这两个方法的不同之处是:
parseXxx()方法返回所指定的基本类型。
valueOf()方法返回新创建的包装对象,对象的类型与调用该方法的类型相同。
5. toString()方法
Object类是java中开篇的类,它具有toString()方法。所有其他java类都继承自Object类,而且所有其他java类都有toString()方法。toString()方法的想法是使你能够获得指定对象的有
意义表示。例如,如果有一个各种类型对象的Collection,则可以遍历该Collection,使用每个类中都具备的toString()方法输出每个的有意义表示。所有包装器类都有toString()的无变元、非静态且为final的实力
版本。例如;
Double d = new Double(“3.14”);
System.out.println(“d = ” + d. toString());
总之,包装器转换方法的实质是:
primitive..xxxValue()------将包装器转换为基本类型
primitive.parseXxx(String)-------将
String转换为基本类型
Wrapper.valueOf(String)--------将String转换为包装器。