小男孩‘自慰网亚洲一区二区,亚洲一级在线播放毛片,亚洲中文字幕av每天更新,黄aⅴ永久免费无码,91成人午夜在线精品,色网站免费在线观看,亚洲欧洲wwwww在线观看

分享

Java對象的序列化與反序列化

 yetao_study 2014-10-21

一、為什么要進行序列化

再介紹之前,我們有必要先了解下對象的生命周期,我們知道Java中的對象都是存在于堆內(nèi)存中的,而堆內(nèi)存是可以被垃圾回收器不定期回收的。從對象被創(chuàng)建到被回收這一段時間就是Java對象的生命周期,也即Java對象只存活于這個時間段內(nèi)。

對象被垃圾回收器回收意味著對象和對象中的成員變量所占的內(nèi)存也就被回收,這意味著我們就再也得不到該對象的任何內(nèi)容了,因為已經(jīng)被銷毀了嘛,當然我們可以再重新創(chuàng)建,但這時的對象的各種屬性都又被重新初始化了。所以如果我們需要保存某對象的狀態(tài),然后再在未來的某段時間將該對象再恢復(fù)出來的話,則必須要在對象被銷毀即被垃圾回收器回收之前保存對象的狀態(tài)。要保存對象狀態(tài)的話,我們可以使用文件、數(shù)據(jù)庫,也可以使用序列化,這里我們主要介紹對象序列化。我們很有必要了解這方面的內(nèi)容,因為對象序列化不僅在保存對象狀態(tài)時可以被用到(對象持久化),在Java中的遠程方法調(diào)用RMI也會被用到,在網(wǎng)絡(luò)中要傳輸對象的話,則必須要對對象進行序列化,關(guān)于RMI有機會我會再專門開貼介紹。

簡單總結(jié)起來,進行對象序列化的話的主要原因就是實現(xiàn)對象持久化和進行網(wǎng)絡(luò)傳輸,這里先只介紹怎樣通過對象序列化保存對象的狀態(tài)。

下面我們通過一個簡單的例子來介紹下如何進行對象序列化。

二、怎樣進行對象序列化

假設(shè)我們要保存Person類的某三個對象的name、age、height這三個成員變量,當然這里只是簡單舉例

我們先看下Person類,要序列化某個類的對象的話,則該類必要實現(xiàn)Serializable接口,從Java API中我們發(fā)現(xiàn)該接口是個空接口,即該接口中沒聲明任何方法。

  1. import java.io.Serializable;  
  2. public class Person implements Serializable {  
  3. int age;  
  4. int height;  
  5. String name;  
  6. public Person(String name, int age, int height){  
  7. this.name = name;  
  8. this.age = age;  
  9. this.height = height;  
  10. }  
  11. }  

下面我們看一下如何來進行序列化,這其中主要涉及到JavaI/O方面的內(nèi)容,主要用到兩個類FileOutputStreamObjectOutputStream,FileOutputStream用于將字節(jié)輸出到文件,ObjectOutputStream通過調(diào)用writeObject方法將對象轉(zhuǎn)換為可以寫出到流的數(shù)據(jù)。所以整個流程是這樣的:ObjectOutputStream將要序列化的對象轉(zhuǎn)換為某種數(shù)據(jù),然后通過FileOutputStream連接某磁盤文件,再對象轉(zhuǎn)化的數(shù)據(jù)轉(zhuǎn)化為字節(jié)數(shù)據(jù)再將其寫出到磁盤文件。下面是具體代碼:
  1. import java.io.FileOutputStream;  
  2. import java.io.IOException;  
  3. import java.io.ObjectOutputStream;  
  4. public class MyTestSer {  
  5. /** 
  6.  * Java對象的序列化與反序列化 
  7.  */  
  8. public static void main(String[] args) {  
  9. Person zhangsan = new Person("zhangsan"30170);  
  10. Person lisi = new Person("lisi"35175);  
  11. Person wangwu = new Person("wangwu"28178);  
  12. try {  
  13. //需要一個文件輸出流和對象輸出流;文件輸出流用于將字節(jié)輸出到文件,對象輸出流用于將對象輸出為字節(jié)  
  14. ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("person.ser"));  
  15. out.writeObject(zhangsan);  
  16. out.writeObject(lisi);  
  17. out.writeObject(wangwu);  
  18. out.close();  
  19. catch (IOException e) {  
  20. e.printStackTrace();  
  21. }  
  22. }  
  23. }  

三、對象的反序列化

我們存儲的目的主要是為了再恢復(fù)使用,下面我們來看下加上反序列化后的代碼:

  1. import java.io.FileInputStream;  
  2. import java.io.FileOutputStream;  
  3. import java.io.IOException;  
  4. import java.io.ObjectInputStream;  
  5. import java.io.ObjectOutputStream;  
  6. public class MyTestSer {  
  7. /** 
  8.  * Java對象的序列化與反序列化 
  9.  */  
  10. public static void main(String[] args) {  
  11. Person zhangsan = new Person("zhangsan"30170);  
  12. Person lisi = new Person("lisi"35175);  
  13. Person wangwu = new Person("wangwu"28178);  
  14. try {  
  15. //需要一個文件輸出流和對象輸出流;文件輸出流用于將字節(jié)輸出到文件,對象輸出流用于將對象輸出為字節(jié)  
  16. ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("person.ser"));  
  17. out.writeObject(zhangsan);  
  18. out.writeObject(lisi);  
  19. out.writeObject(wangwu);  
  20. catch (IOException e) {  
  21. e.printStackTrace();  
  22. }  
  23. try {  
  24. ObjectInputStream in = new ObjectInputStream(new FileInputStream("person.ser"));  
  25. Person one = (Person) in.readObject();  
  26. Person two = (Person) in.readObject();  
  27. Person three = (Person) in.readObject();  
  28. System.out.println("name:"+one.name + " age:"+one.age + " height:"+one.height);  
  29. System.out.println("name:"+two.name + " age:"+two.age + " height:"+two.height);  
  30. System.out.println("name:"+three.name + " age:"+three.age + " height:"+three.height);  
  31. catch (Exception e) {  
  32. e.printStackTrace();  
  33. }  
  34. }  
  35. }  

輸出結(jié)果如下:

  1. name:zhangsan age:30 height:170  
  2. name:zhangsan age:35 height:175  
  3. name:zhangsan age:28 height:178  

從添加的代碼我們可以看到進行反序列化也很簡單,主要用到的流是FileInputstreamObjectInputstream正好與存儲時用到的流相對應(yīng)。另外從結(jié)果順序我們可以看到反序列化后得到對象的順序與序列化時的順序一致。

四、總結(jié)

進行對象序列化主要目的是為了保存對象的狀態(tài)(成員變量)。

進行序列化主要用到的流是FileOutputStreamObjectOutputStream。FileOutputStream主要用于連接磁盤文件,并把字節(jié)寫出到該磁盤文件;ObjectOutputStream主要用于將對象寫出為可轉(zhuǎn)化為字節(jié)的數(shù)據(jù)。

要將某類的對象序列化,則該類必須實現(xiàn)Serializable接口,該接口僅是一個標志,告訴JVM該類的對象可以被序列化。如果某類未實現(xiàn)Serializable接口,則該類對象不能實現(xiàn)序列化。

保存狀態(tài)的目的就是為了在未來的某個時候再恢復(fù)保存的內(nèi)容,這可以通過反序列化來實現(xiàn)。對象的反序列化過程與序列化正好相反,主要用到的兩個流是FileInputstreamObjectInputStream。

反序列化后得到的對象的順序與保存時的順序一致。

五、補充

補充一:上面我們舉得例子很簡單,要保存的成員變量要么是基本類型的要么是String類型的。但有時成員變量有可能是引用類型的,這是的情況會復(fù)雜一點。那就是當要對某對象進行序列化時,該對象中的引用變量所引用的對象也會被同時序列化,并且該對象中如果也有引用變量的話則該對象也將被序列化。總結(jié)說來就是在序列化的時候,對象中的所有引用變量所對應(yīng)的對象將會被同時序列化。這意味著,引用變量類型也都要實現(xiàn)Serializable接口。當然其他對象的序列化都是自動進行的。所以我們只要保證里面的引用類型是都實現(xiàn)Serializable接口就行了,如果沒有的話,會在編譯時拋出異常。如果序列化的對象中包含沒有實現(xiàn)Serializable的成員變量的話,這時可以使用transient關(guān)鍵字,讓序列化的時候跳過該成員變量。使用關(guān)鍵字transient可以讓你在序列化的時候自動跳過transient所修飾的成員變量,在反序列化時這些變量會恢復(fù)到默認值。

補充二:如果某類實現(xiàn)了Serializable接口的話,其子類會自動編程可序列化的,這個好理解,繼承嘛。

補充三:在反序列化的時候,并不會調(diào)用對象的構(gòu)造器,這也好理解,如果調(diào)用了構(gòu)造器的話,對象的狀態(tài)不就又重新初始化了嗎。

補充四:我們說到對象序列化的是為了保存對象的狀態(tài),即對象的成員變量,所以靜態(tài)變量不會被序列化。

    本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊一鍵舉報。
    轉(zhuǎn)藏 分享 獻花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多