对象包装器
有时,需要将基本数据类型转换成对象。所有的基本类型都有一个与之对应的类。
基本数据类型有:byte、short、int、long、float、double、char、boolean,其对应的对象包装器(object wrapper)分别是:Byte,Short,Integer,Long,Float,Double,Character,Boolean。(前6个类派生于公共的超类Number)。
对象包装器类是不可变的,**即一旦构造了包装器,就不允许更改在其中的值。**同时,对象包装器类还是final,因此不能定义它们的子类。
假设想定义一个整型数组列表。而尖括号中的类型参数不允许是基本类型,也就是说,不允许写成ArrayList。这里就用到了Integer对象包装器类。我们可以声明一个Integer对象的数组列表:ArrayList list = new ArrayList;
注意:由于每个值分别包装在对象中,所以ArrayList的效率远远低于int[]数组。
自动装箱
其实调用list.add(3),就等同于调用list.add(Integer.valueOf(3));这种变化就成为自动装箱。
相反的,当将一个Integer对象赋给一个int值时,将会自动地拆箱。也就是说,编译器将下列语句:
int n = list.get(i);
翻译成:
int n = list.get(i).intValue();
甚至在算术表达式中也能够自动地装箱和拆箱。如:
Integer n = 3;
n++;
编译器将自动地插入一条对象拆箱的指令,然后进行自增计算,最后再将结果装箱。
大多数情况下,容易给我们造成一种假象,觉得基本类型与它们的对象包装器是一样的。"=="也可以用于比较对象包装器对象,但是比较的是存储区域。
//下面这种情况并不会成立
Integer a = 1000;
Integer b = 1000;
System.out.println(a==b); //false
//如果a.b改成127,则结果为true。
Integer a = 127;
Integer b = 127;
System.out.println(a==b); //true
**注释:**介于-128~127之间的short和int被包装到固定的对象中。故再此区间内的数字对应的存储地址也是相同的。
自动装箱的几点说明:
- 由于包装器引用可以为null,所以自动装箱有可能会抛出一个NullPointerException异常
- 如果在一个条件表达式中混合使用Integer和Double类型,Integer值就会拆箱,int提升为double,再装箱为Double。
- **装箱和拆箱是编译器认可的,**而不是虚拟机。编译器在生成类的字节码时,插入必要的方法调用。虚拟机只是执行这些字节码。(有待深究)
自动装箱的好处
可以将某些基本方法放置在包装器中,例如:将一个数字字符串转换成数值。
int x = Integer.parseInt(s);
这里与Integer对象没有任何关系,parseInt是一个静态方法。但Integer类是放置这个方法的好地方。
注意: 包装器类不可以用来实现修改数值再赋予数值本身。Integer 对象是不可变的: 包含在包装器中的内容不会改变: 不能使用这些包装器类创建修改数值参数的方法。如果想编写一个修改数值参数值的方法, 就需要使用在 org.omg.CORBA 包中定义的持有者( holder) 类型, 包括 IntHolder、BooleanHolder 等。每个持有者类型都包含’一个公有 (!)域值,通过它可以访问存储在其中的值。
import org.omg.CORBA.IntHolder;
public class WrapperTest {
public static void triple(int x) {
x = 3 * x;
}
public static void triple1(Integer x) {
x = 3 * x;
}
public static void triple2(IntHolder x) {
x.value = 3 * x.value;
}
public static void main(String[] args) {
int x1 = 1;
triple(x1);
System.out.println(x1); //1
System.out.println("=========================");
int x2 = 1;
triple1(x2);
System.out.println(x2); //1
System.out.println("=========================");
IntHolder x3 = new IntHolder(1);
triple2(x3);
System.out.println(x3.value); //3
}
/**
* 结果:
* 1
* =========================
* 1
* =========================
* 3
*/
//如果是赋予不同的变量,那自然是可以的,因为赋予给一个新的地址了
public static int triple4(int x) {
int y = 3 * x;
return y;
}
public static int triple5(Integer x) {
int y = 3 * x;
return y;
}
public static void main(String[] args) {
int x4 = 1;
System.out.println(triple4(x4)); //3
int x5 = 1;
System.out.println(triple5(x5)); //3
}