java 自动装箱拆箱

基本数据 (Primitive) 类型的自动装箱 (autoboxing)、拆箱(unboxing) 是自 J2SE 5.0 开始提供的功能。java 语言规范中说道:在许多情况下包装与解包装是由编译器自行完成的(在这种情况下包装成为装箱,解包装称为拆箱)

这个是 jdk1.5 以后才引入的新的内容,作为秉承发表是最好的记忆,毅然决定还是用一篇博客来代替我的记忆:
java 语言规范中说道:在许多情况下包装与解包装是由编译器自行完成的(在这种情况下包装成为装箱,解包装称为拆箱);
其实按照我自己的理解自动装箱就可以简单的理解为将基本数据类型封装为对象类型,来符合 java 的面向对象;例如用 int 来举例:

//声明一个Integer对象 
Integer num = 10; 
//以上的声明就是用到了自动的装箱:解析为 
Integer num = new Integer(10);/*以上就是一个很好的体现,因为10是属于基本数据类型的,原则上它是不能直接赋值给一个对象Integer的,但jdk1.5后你就可以进行这样的声明,这就是自动装箱的魅力 
自动将基本数据类型转化为对应的封装类型。成为一个对象以后就可以调用对象所声明的所有的方法 
自动拆箱:故名思议就是将对象重新转化为基本数据类型: */
//装箱 
Integer num = 10; 
//拆箱 
int num1 = num; //自动拆箱有个很典型的用法就是在进行运算的时候:因为对象时不恩直接进行运算的,而是要转化为基本数据类型后才能进行加减乘除 
Integer num = 10; 
//进行计算时隐含的有自动拆箱 
System.out.print(num--); //哈哈 应该感觉很简单吧,下面我再来讲点稍微难点的, 
//在-128~127 之外的数 
Integer num1 = 297; Integer num2 = 297; 
System.out.println("num1==num2: "+(num1==num2)); 
// 在-128~127 之内的数 
Integer num3 = 97; Integer num4 = 97; 
System.out.println("num3==num4: "+(num3==num4)); 打印的结果是:num1==num2: false num3==num4: true 

很奇怪吧:这就归结于 java 对于 Integer 与 int 的自动装箱与拆箱的设计,是一种模式:叫享元模式(flyweight)
为了加大对简单数字的重利用,java 定义:在自动装箱时对于值从–128 到 127 之间的值,它们被装箱为 Integer 对象后,会存在内存中被重用,始终只存在一个对象
而如果超过了从–128 到 127 之间的值,被装箱后的 Integer 对象并不会被重用,即相当于每次装箱时都新建一个 Integer 对象;明白了吧
以上的现象是由于使用了自动装箱所引起的,如果你没有使用自动装箱,而是跟一般类一样,用 new 来进行实例化,就会每次 new 就都一个新的对象;
这个的自动装箱拆箱不仅在基本数据类型中有应用,在 String 类中也有应用,比如我们经常声明一个 String 对象时:


String str = "sl"; 
//代替下面的声明方式 
String str = new String("sl"); 

基本数据 (Primitive) 类型的自动装箱 (autoboxing)、拆箱(unboxing) 是自 J2SE 5.0 开始提供的功能。虽然为您打包基本数据类型提供了方便,但提供方便的同时表示隐藏了细节,建议在能够区分基本数据类型与对象的差别时再使用。
autoboxing 和 unboxing
在 Java 中,所有要处理的东西几乎都是对象 (Object),例如之前所使用的 Scanner 是对象,字符串 (String) 也是对象,之后还会看到更多的对象。然而基本 (Primitive) 数据类型不是对象,也就是您使用 int、double、boolean 等定义的变量,以及您在中直接写下的字面常量。
在前一个小节中已经大致看到了操作对象的方便性,而使用 Java 有一段时间的人都知道,有时需要将基本数据类型转换为对象。例如使用 Map 对象要 put() 方法时,需要传入的参数是对象而不是基本数据类型。
要使用打包类型 (Wrapper Types) 才能将基本数据类型包装为对象,前一个小节中您已经知道在 J2SE 5.0 之前,要使用以下语句才能将 int 包装为一个 Integer 对象:Integer integer = new Integer(10);
在 J2SE 5.0 之后提供了自动装箱的功能,您可以直接使用以下语句来打包基本数据类型:Integer integer = 10;
在进行编译时,编译器再自动根据您写下的语句,判断是否进行自动装箱动作。在上例中 integer 参考的会是 Integer 类的实例。同样的动作可以适用于 boolean、byte、short、char、long、float、double 等基本数据类型,分别会使用对应的打包类型 (Wrapper Types)Boolean、Byte、Short、Character、Long、Float 或 Double。下面直接使用自动装箱功能来改写范例 4.4。

范例 4.5 AutoBoxDemo.java


public class AutoBoxDemo { 
public static void main(String[] args) { 
Integer data1 = 10; 
Integer data2 = 20; 
// 转为double值再除以3 
System.out.println(data1.doubleValue() / 3); 
// 进行两个值的比较 
System.out.println(data1.compareTo(data2)); 
} 
} 

程序看来简洁了许多,data1 与 data2 在运行时就是 Integer 的实例,可以直接进行对象操作。的结果如下:
3.3333333333333335
–1
自动装箱运用的方法还可以如下:


int i = 10; 
Integer integer = i; 

也可以使用更一般化的 java.lang.Number 类来自动装箱。例如:
Number number = 3.14f;
3.14f 会先被自动装箱为 Float,然后指定给 number。
从 J2SE 5.0 开始可以自动装箱,也可以自动拆箱 (unboxing),也就是将对象中的基本数据形态信息从对象中自动取出。例如下面这样写是可以的:

Integer fooInteger = 10; 
int fooPrimitive = fooInteger; 

fooInteger 引用至自动装箱为 Integer 的实例后,如果被指定给一个 int 类型的变量 fooPrimitive,则会自动变为 int 类型再指定给 fooPrimitive。在运算时,也可以进行自动装箱与拆箱。例如:

Integer i = 10; 
System.out.println(i + 10); 
System.out.println(i++); 

上例中会显示 20 与 10,编译器会自动进行自动装箱与拆箱,也就是 10 会先被装箱,然后在 i + 10 时会先拆箱,进行加法运算;i++ 该行也是先拆箱再进行递增运算。再来看一个例子:


Boolean boo = true; 
System.out.println(boo && false); 

同样的 boo 原来是 Boolean 的实例,在进行 AND 运算时,会先将 boo 拆箱,再与 false 进行 AND 运算,结果会显示 false。
//////////////////////////////////////////////////////////////////
装箱:从基本类型转换成 Object 类型,称之为装箱;*** 拆箱:从 Object 转换乘基本类型的操作,称之为拆箱。 这个操作在反射过程中用的比较的多。
装箱:在堆中建立一个 Object 实例,把你指定的值复制成去;*** 拆箱:判别引用指向的堆中信息是否是要拆成的类型,是取出堆中值送给栈中变量,否则报异常
///////////////////////////////////////////////////////////////////
装箱是值类型到 object 类型或到该值类型所实现的任何接口类型的隐士转换。
将一个值类型装箱会分配一个对象实例并将该值复制到新的对象中。


int i=123; 
object o=i; 

这句话的结果是在堆栈上创建一个对象 o, 而该对象在堆上引用 int 类型的值。该值是赋值给变量 i
的值类型值的一个副本。
下面是显示执行装箱转换


int i=123; 
ojbect o=(object)i; 

此例将整数变量 i 通过装箱转换为对象 o。这样,存储在变量 i 中的值就从 123 改为 456。此例显示对象保留了内容的原始副本。即 123。
取消装箱是从 object 类型到值类型或从接口类型到实现该接口的值类型的显示转换。取消装箱操作包括:
检查对象实例,确保它是给定值类型的一个装箱值。
将该值从实例复制到值类型变量中。
例子:


int i=123; 
object box=i; 
int j=(int)box;