Java SE5引入了自动包装机制,可以自动的实现基本类型和对象类型的双向转换,例如int类型和Integer类型的相互转换。
在Java中,除了基本类型以外,其他都是以对象的形式存在。而每种基本类型也有其对应的类,这些类被称为包装器(Wrapper)。
例如:
基本类型 | 对应的类 |
---|---|
int | Integer |
double | Double |
以下 | 同理 |
这些类就属于不可变对象。
通常我们创建一个类时,会设置相应的get和set方法来对成员进行修改。但是对于不可变对象而言,内部成员的值是不能被修改到的,所以被称为不可变。
对于用户自定义的类而言,若想设计成不可变对象,可以借助private或者final关键字防止使用者来修改对象内部的值。
对于Integer这些对象包装器来说,他们不能够被继承,也不能修改内部的值。(因为他们其实就是final类)例如,调用构造函数: new Integer(1) 来实例化一个内部保存了一个int=1的Integer对象,这个对象内部的值再也不能被修改了。这样做的好处是,将Java里的所有基本类型都统一为了对象,而且可以将一些工具类放入包装器中。所以当我们想定义一个整数数组列表时,因为<>尖括号中是不允许是基本类型的,这时候就可以使用Integer对象包装器类。但是在数组列表中,调用list.add()方法时,可以直接传入一个整数类型int,这是因为Java中存在有自动包装机制。
自动装箱和拆箱
基本类型和基本类型所对应的对象,可以自动完成装箱和拆箱操作,即可以自动地相互转换。例如:
package s1;
public class V {
public static void main(String[] args) {
int i1 = new Integer(1);
Integer integer1 = 1;
test1(1);
test1(new Integer(1));
test2(1);
test2(new Integer(1));
Integer integer2 = 1;
Integer integer3 = new Integer(3);
integer2++;
integer3++;
}
static void test1(int i) {
}
static void test2(Integer integer) {
}
}
Integer不能参与运算,这里会发生拆箱动作,将Integer类变成基本类型int参与运算,执行自增动作,在运算结束之后,再自动装箱。
关于自动装箱还有几点需要注意:
1、由于包装器类的引用可以为null
,所以在拆箱的时候会抛出NullPointerException
2、在一个条件表达式中混合使用Integer和Double类型,Integer值会拆箱,提升为double,再装箱为Double
Java在栈里设计了一个静态常量池,里面已经准备好了一些会经常用到的数字[0~127]或者字符串(比如"abc"),所以当实例化对象的值在常量池里有的时候,Java不会去堆中再开辟新的空间,而是直接指向栈内的那个值。
例如:
package s1;
public class W {
public static void main(String[] args) {
int i1 = 10;
Integer integer1 = 10; //数字10会自动装箱成Integer,此时integer指向常量区存放数字10的地址
Integer integer2 = new Integer(10); //integer2指向堆栈区
// 和基本类型比较,比较的是数值而非对象引用,因此Integer会被拆箱成int
System.out.println(i1 == integer1); // true
System.out.println(integer1 == i1); // true
System.out.println(integer2 == i1); // true
System.out.println(integer1 == integer2); // false,对象类型比较,比较的是所指向的内存地址是否一致
Integer integer4 = new Integer(5);
Integer integer5 = new Integer(5);
// integer4 + integer5先执行拆箱,然后执行加法操作,成为基本类型
System.out.println(i1 == (integer4 + integer5)); //true
System.out.println(integer1 == (integer4 + integer5)); //true
System.out.println(integer2 == (integer4 + integer5)); //true
Integer integer6 = integer4 + integer5;
System.out.println(i1 == integer6); //true,和基本类型比较,比较的是数值
System.out.println(integer1 == integer6); //都是指向常量区存放数字10的地址
System.out.println(integer2 == integer6); //false,integer2指向堆栈区,integer指向常量区
Integer integer7 = 127;
Integer integer8 = 127;
System.out.println(integer7 == integer8); //true,数值在[0~127]范围类,二者指向常量区的同一对象的地址
Integer integer9 = 128;
Integer integer10 = 128;
System.out.println(integer9 == integer10); //false,128已经超过127,不会存在常量区,而是在存在堆栈区的两个不同对象
Integer[] array = new Integer[2];
array[0] = 127;
array[1] = 127;
System.out.println(array[0] == array[1]); // true,数值在[0~127]范围类,二者指向常量区的同一对象的地址
array[0] = 128;
array[1] = 128;
System.out.println(array[0] == array[1]); //false,128已经超过127,不会存在常量区,而是在存在堆栈区的两个不同对象
}
}