Bootstrap

Java对象包装器与自动打包

所有基本类型都有一个与之对应的类,例如,Integer类对应基本类型int。通常,这些类称为包装器(wrapping)。这些对象包装器拥有很鲜明的名字:Integer、Long、Float、Double、Short、Byte、Character、Void和Boolean(前面六个类派生于公共的超类Number)。对象包装器类是不可变的,一旦构造了包装器,就不允许更改包装器里面的值。同时,对象包装器还是final,因此不能定义他们的子类。

定义一个整形数组列表,尖括号里面的参数类型不允许是基本类型,也就是说不允许写成ArrayList<int>。这里就用到了Integer对象包装器类。我们可以声明一个Integer对象的数组列表。

ArrayList<Integer> list = new ArrayList<Integer>;
当调用:

list.add(3);
将自动变换成:

list.add(new Integer(3));
这种变换称之自动打包(autoboxing)。

相反的如果将Integer对象赋值给一个int值时,将会自动第拆包。也就是说编译器将下列语句:

int n = list.get(i);
翻译成:

int n = list.get(i).intValue();
甚至在算术表达式中也能够自动的打包和拆包。例如,可以将自增操作符应用于一个包装器引用:

Integer n = 3;
n++;
编译器将自动第插入一条拆开对象包的指令,然后进行自增运算,最后再将结果打入对象包内。

很多情况下,容易有一种假象,即基本类型和他们的对象包装类是一样的,只是他们的相等性不同,==运算符也可以用于包装器对象,只不过检测的是对象是否指向同一个存储区域。

先看下面一段代码:

public class Main {
    public static void main(String[] args) {
         
        Integer i1 = 100;
        Integer i2 = 100;
        Integer i3 = 200;
        Integer i4 = 200;
         
        System.out.println(i1==i2);
        System.out.println(i3==i4);
    }
}
输出结果为:true,false。 结果表明i1和i2指向的是同一个对象,而i3和i4指向的是不同的对象。下面这段代码是Integer的valueOf方法的具体实现:

public static Integer valueOf(int i) {
        if(i >= -128 && i <= IntegerCache.high)
            return IntegerCache.cache[i + 128];
        else
            return new Integer(i);
    }

自动打包要求规范要求boolean、byte、char<=127,介于-128~127之间的short和int被包装到固定的对象中,否则创建一个新的对象。如上面的i1和i2初始化为100,对他们的比较的结果一定是成立的。

所以在比较两个包装器对象的值是否相等时调用equals方法就能避免出现false的情况。

最后说明一下,打包和拆包是编译器认可的,而不是虚拟机。编译器在生成类的字节码时插入必要的方法调用。虚拟机只是执行这些字节码。





;