Java 序列化Serializable詳解(附詳細例子)

    Java 序列化Serializable詳解(附詳細例子) 

1、什麼是序列化和反序列化
Serialization(序列化)是一種將對象以一連串的字節描述的過程;反序列化deserialization是一種將這些字節重建成一個對象的過程。


2、什麼情況下需要序列化 
a)當你想把的內存中的對象保存到一個文件中或者數據庫中時候;
b)當你想用套接字在網絡上傳送對象的時候;
c)當你想通過RMI傳輸對象的時候;

3、如何實現序列化

將需要序列化的類實現Serializable接口就可以了,Serializable接口中沒有任何方法,可以理解爲一個標記,即表明這個類可以序列化。


4、序列化和反序列化例子

如果我們想要序列化一個對象,首先要創建某些OutputStream(如FileOutputStream、ByteArrayOutputStream等),然後將這些OutputStream封裝在一個ObjectOutputStream中。這時候,只需要調用writeObject()方法就可以將對象序列化,並將其發送給OutputStream記住:對象的序列化是基於字節的,不能使用Reader和Writer等基於字符的層次結構。而反序列的過程(即將一個序列還原成爲一個對象),需要將一個InputStream(如FileInputstream、ByteArrayInputStream等)封裝在ObjectInputStream內,然後調用readObject()即可。

[java] view plain copy
  1. package com.sheepmu;  
  2. import java.io.FileInputStream;  
  3. import java.io.FileNotFoundException;  
  4. import java.io.FileOutputStream;  
  5. import java.io.IOException;  
  6. import java.io.ObjectInputStream;  
  7. import java.io.ObjectOutputStream;  
  8. import java.io.Serializable;  
  9.   
  10. public class MyTest implements Serializable  
  11. {  
  12.     private static final long serialVersionUID = 1L;  
  13.     private String name="SheepMu";  
  14.     private int age=24;  
  15.     public static void main(String[] args)  
  16.     {//以下代碼實現序列化  
  17.         try   
  18.         {  
  19.             ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("my.out"));//輸出流保存的文件名爲 my.out ;ObjectOutputStream能把Object輸出成Byte流  
  20.             MyTest myTest=new MyTest();  
  21.             oos.writeObject(myTest);   
  22.             oos.flush();  //緩衝流   
  23.             oos.close(); //關閉流  
  24.         } catch (FileNotFoundException e)   
  25.         {          
  26.             e.printStackTrace();  
  27.         } catch (IOException e)   
  28.         {  
  29.             e.printStackTrace();  
  30.         }   
  31.         fan();//調用下面的  反序列化  代碼  
  32.     }  
  33.     public static void fan()//反序列的過程  
  34.     {      
  35.          ObjectInputStream oin = null;//局部變量必須要初始化  
  36.         try  
  37.         {  
  38.             oin = new ObjectInputStream(new FileInputStream("my.out"));  
  39.         } catch (FileNotFoundException e1)  
  40.         {          
  41.             e1.printStackTrace();  
  42.         } catch (IOException e1)  
  43.         {  
  44.             e1.printStackTrace();  
  45.         }        
  46.         MyTest mts = null;  
  47.         try {  
  48.             mts = (MyTest ) oin.readObject();//由Object對象向下轉型爲MyTest對象  
  49.         } catch (ClassNotFoundException e) {  
  50.             e.printStackTrace();  
  51.         } catch (IOException e) {  
  52.             e.printStackTrace();  
  53.         }       
  54.          System.out.println("name="+mts.name);      
  55.          System.out.println("age="+mts.age);      
  56.     }  
  57. }  
會在此項目的工作空間生成一個 my.out文件。序列化後的內容稍後補齊,先看反序列化後輸出如下:

name=SheepMu
age=24

5、序列化ID

序列化 ID 在 Eclipse 下提供了兩種生成策略,一個是固定的 1L,一個是隨機生成一個不重複的 long 類型數據(實際上是使用 JDK 工具生成),在這裏有一個建議,如果沒有特殊需求,就是用默認的 1L 就可以,這樣可以確保代碼一致時反序列化成功。這也可能是造成序列化和反序列化失敗的原因,因爲不同的序列化id之間不能進行序列化和反序列化。


6.序列化前和序列化後的對象的關係

是 "=="還是equal? or  是淺複製還是深複製? 

答案:深複製,反序列化還原後的對象地址與原來的的地址不同

序列化前後對象的地址不同了,但是內容是一樣的,而且對象中包含的引用也相同。換句話說,通過序列化操作,我們可以實現對任何可Serializable對象的”深度複製(deep copy)"——這意味着我們複製的是整個對象網,而不僅僅是基本對象及其引用。對於同一流的對象,他們的地址是相同,說明他們是同一個對象,但是與其他流的對象地址卻不相同。也就說,只要將對象序列化到單一流中,就可以恢復出與我們寫出時一樣的對象網,而且只要在同一流中,對象都是同一個。


7.靜態變量能否序列化

若把上面的代碼中的 age變量前加上 static ,輸出任然是

name=SheepMu
age=24

但是看下面的例子:

[java] view plain copy
  1. package com.sheepmu;  
  2. import java.io.FileInputStream;  
  3. import java.io.FileNotFoundException;  
  4. import java.io.FileOutputStream;  
  5. import java.io.IOException;  
  6. import java.io.ObjectInputStream;  
  7. import java.io.ObjectOutputStream;  
  8. import java.io.Serializable;  
  9. public class MyTest implements Serializable  
  10. {  
  11.     private static final long serialVersionUID = 1L;  
  12.     private String name="SheepMu";  
  13.     private static int age=24;  
  14.     public static void main(String[] args)  
  15.     {//以下代碼實現序列化  
  16.         try   
  17.         {  
  18.             ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("my.out"));//輸出流保存的文件名爲 my.out ;ObjectOutputStream能把Object輸出成Byte流  
  19.             MyTest myTest=new MyTest();  
  20.             oos.writeObject(myTest);   
  21.             oos.flush();  //緩衝流   
  22.             oos.close(); //關閉流  
  23.         } catch (FileNotFoundException e)   
  24.         {          
  25.             e.printStackTrace();  
  26.         } catch (IOException e)   
  27.         {  
  28.             e.printStackTrace();  
  29.         }   
  30.         fan();//調用下面的  反序列化  代碼  
  31.     }  
  32.     public static void fan()  
  33.     {  
  34.         new MyTest().name="SheepMu_1";     //!!!!!!!!!!!!!!!!重點看這兩行 更改部分  
  35.         age=1;        //!!!!!!!!!!!!!!!!!!!重點看這兩行 更改部分   
  36.          ObjectInputStream oin = null;//局部變量必須要初始化  
  37.         try  
  38.         {  
  39.             oin = new ObjectInputStream(new FileInputStream("my.out"));  
  40.         } catch (FileNotFoundException e1)  
  41.         {          
  42.             e1.printStackTrace();  
  43.         } catch (IOException e1)  
  44.         {  
  45.             e1.printStackTrace();  
  46.         }        
  47.         MyTest mts = null;  
  48.         try {  
  49.             mts = (MyTest ) oin.readObject();//由Object對象向下轉型爲MyTest對象  
  50.         } catch (ClassNotFoundException e) {  
  51.             e.printStackTrace();  
  52.         } catch (IOException e) {  
  53.             e.printStackTrace();  
  54.         }       
  55.          System.out.println("name="+mts.name);      
  56.          System.out.println("age="+mts.age);      
  57.     }  
  58. }  
輸出結果爲:

name=SheepMu
age=1
爲何把最上面代碼的age變量添上static 後還是反序列化出了24呢?而新的從新對變量賦值的代碼,不是static的得到了序列化本身的值,而static的則得到的是從新附的值。原因: 序列化會忽略靜態變量,即序列化不保存靜態變量的狀態。靜態成員屬於類級別的,所以不能序列化。即 序列化的是對象的狀態不是類的狀態。這裏的不能序列化的意思,是序列化信息中不包含這個靜態成員域。最上面添加了static後之所以還是輸出24是因爲該值是
JVM加載該類時分配的值。注:transient後的變量也不能序列化但是情況稍複雜,稍後開篇說。

8、總結:

a)當一個父類實現序列化,子類自動實現序列化,不需要顯式實現Serializable接口;

b)當一個對象的實例變量引用其他對象,序列化該對象時也把引用對象進行序列化;

c) static,transient後的變量不能被序列化;



文章轉載自CSDN博主SheepMuJava序列化serialzable詳解(附詳細例子)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章