原文連接:https://blog.csdn.net/u011215133/article/details/51177843java
簡單來講序列化就是一種用來處理對象流的機制。所謂對象流也就是將對象的網絡
內容進行流化,流的概念這裏不用多說(就是I/O)。咱們能夠對流化後的對象進行讀寫spa
操做,也可將流化後的對象傳輸於網絡之間(注:要想將對象傳輸於網絡必須進行流化)!.net
在對對象流進行讀寫操做時會引起一些問題,而序列化機制正是用來解決這些問題的!code
-----------------------------------------------------------------------------------------小分割線
問題的引出:
如上所述,讀寫對象會有什麼問題呢?好比:我要將對象寫入一個磁盤文件然後再將對象
其讀出來會有什麼問題嗎?別急,其中一個最大的問題就是對象引用!blog
舉個例子來講:假如我有兩個類,分別是A和B,B類中含有一個指向A類對象的引用,接口
如今咱們對兩個類進行實例化{ A a = new A(); B b = new B(); }。這時在內存中實際上分配內存
了兩個空間,一個存儲對象a,一個存儲對象b。接下來咱們想將它們寫入到磁盤的一個文件get
中去,就在寫入文件時出現了問題!由於對象b包含對對象a的引用,因此係統會自動的將a
的數據複製一份到b中,這樣的話當咱們從文件中恢復對象時(也就是從新加載到內存中)時,
內存分配了三個空間,而對象a同時在內存中存在兩份,想想後果吧,若是我想修改對象a
的數據的話,那不是還要搜索它的每一份拷貝來達到對象數據的一致性,這不是咱們所但願的!
-----------------------------------------------------------------------------------------小分割線
如下序列化機制的解決方案:
1.保存到磁盤的全部對象都得到一個序列號(1, 2, 3等等)
2.當要保存一個對象時,先檢查該對象是否被保存了
3.若是之前保存過,只需寫入"與已經保存的具備序列號x的對象相同"的標記,不然,保存該對象
經過以上的步驟序列化機制解決了對象引用的問題!
-----------------------------------------------------------------------------------------小分割線
序列化的實現
將須要被序列化的類實現Serializable接口,該接口沒有須要實現的方法,implements Serializable
只是爲了標註該對象是可被序列化的。而後使用一個輸出流(如:FileOutputStream)來構造一個
ObjectOutputStream(對象流)對象。接着,使用ObjectOutputStream對象的writeObject(Object obj)方法
就能夠將參數爲obj的對象寫出(即保存其狀態),要恢復的話則用輸入流。
在序列化的過程當中,有些數據字段咱們不想將其序列化,對於此類字段咱們只須要在定義
時給它加上transient關鍵字便可,對於transient字段序列化機制會跳過不會將其寫入文件,固然
也不可被恢復。但有時咱們想將某一字段序列化,但它在SDK中的定義倒是不可序列化的類型,
這樣的話咱們也必須把他標註爲transient,但是不能寫入又怎麼恢復呢?好在序列化機制爲包含
這種特殊問題的類提供了以下的方法定義:
private void readObject(ObjectInputStream in) throws
IOException, ClassNotFoundException;
private void writeObject(ObjectOutputStream out) throws
IOException;
(注:這些方法定義時必須是私有的,由於不須要你顯示調用,序列化機制會自動調用的)
使用以上方法咱們能夠手動對那些你又想序列化又不能夠被序列化的數據字段進行寫出和讀入操做。
======================================================================分割線
下面是一個典型的例子,java.awt.geom包中的Point2D.Double類就是不可序列化的,由於該類
沒有實現Serializable接口,在個人例子中將把它看成LabeledPoint類中的一個數據字段,並演示
如何將其序列化!
package kunpu.serialize; import java.awt.geom.Point2D; import java.io.*; public class TransientTest { public static void main(String[] args) { LabeledPoint label = new LabeledPoint("Book", 5.00, 5.00); try { System.out.println(label); // 寫入前 ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("Label.txt")); out.writeObject(label); //經過對象輸出流,將label寫入流中 out.close(); System.out.println(label);// 寫入後 ObjectInputStream in = new ObjectInputStream(new FileInputStream("Label.txt")); LabeledPoint label1 = (LabeledPoint) in.readObject(); in.close(); System.out.println(label1);// 讀出並加1.0後 } catch (Exception e) { e.printStackTrace(); } } } class LabeledPoint implements Serializable { private String label; transient private Point2D.Double point; //由於不可被序列化,因此須要加transient關鍵字 public LabeledPoint(String str, double x, double y)//構造方法 { label = str; point = new Point2D.Double(x, y); //此類Point2D.Double不可被序列化 } //由於Point2D.Double不可被序列化,因此須要實現下面兩個方法 private void writeObject(ObjectOutputStream out) throws IOException { out.defaultWriteObject(); out.writeDouble(point.getX()); out.writeDouble(point.getY()); } private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { in.defaultReadObject(); double x = in.readDouble() + 1.0; double y = in.readDouble() + 1.0; point = new Point2D.Double(x, y); } //重寫toString方法 public String toString() { return getClass().getName()+ "[label = " + label+ ", point.getX() = " + (point == null ? "null" : point.getX())+ ", point.getY() = " + (point == null ? "null" : point.getY())+ "]"; } }
序列化和反序列化是I/O的ObjectOutputStream和ObjectInputrStream進行實現的