首頁  >  文章  >  Java  >  java自動裝箱拆箱深入剖析

java自動裝箱拆箱深入剖析

高洛峰
高洛峰原創
2017-01-24 14:16:011491瀏覽

這個是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;

更多java自动装箱拆箱深入剖析相关文章请关注PHP中文网!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn