爲何須要序列化??(轉)

爲何須要序列化

注意:「爲避免編譯錯誤,爲可序列化的類添加了無參數構造函數。」 html

MSDN的定義:序列化是將對象狀態轉換爲可保持或可傳輸的形式的過程。序列化的補集是反序列化,後者將流轉換爲對象。這兩個過程一塊兒保證數據易於存儲和傳輸。 java

你們關心的是爲何須要序列化,用傳統的方法也能實現這種需求嗎,它存在的價值是什麼,低層的原理、實質、基因的區別是什麼?這也是個人疑問,經過在網上搜集,找到了較滿意的答案,分享給你們。 編程

答案一:序列化是用來通訊的,服務端把數據序列化,發送到客戶端,客戶端把接收到的數據反序列化後對數據進行操做,完成後再序列化發送到服務端,服務端再反序列化數據後對數據進行操做。說白了,數據須要序列化之後才能在服務端和客戶端之間傳輸。這個服務端和客戶端的概念是廣義的,能夠在網絡上,也能夠在同一臺機器的不一樣進程中,甚至在同一個進程中進行通訊。在傳統編程中,對象是經過調用棧間接的與客戶端交互,但在面向服務的編程中,客戶端永遠都不會直接調用實例。不知道說的明不明白。 

好吧,我說的確實不夠明白,你問的是爲何須要序列化,我只是說了序列化的一個應用。那我就來講說序列化的好處吧。不序列化也能夠傳輸,可是沒法跨平臺,安全性也沒法保障。我說的是面向服務編程中的做用,在傳統編程中,你在表示層實例化一個業務對象,而後調用業務對象中的方法,你想過爲何能這樣調用嗎?這樣作耦合度過高,很很差。若是序列化之後經過特定的協議傳輸數據就不同了,表示層經過代理或通道向服務層發送特定的數據格式,這個數據就是序列化之後的,好比XML,服務端接收到之後要進行反序列化,生成服務端可識別的數據格式,好比一個類,而後對數據進行操做,再序列化發送到客戶端,客戶端再反序列化。這樣客戶端可使用和服務端徹底不一樣的開發平臺,只要它可以對xml數據進行反序列化,而xml是具備工業標準的數據格式,基本各平臺都支持。這也適用於在進程間通訊。若是在進程內通訊,也能夠作到更高的安全性,對象再也不經過調用棧交互,而是經過代理或通道。 安全

轉自:http://zhidao.baidu.com/question/311731521.html 網絡

答案二:這個更進一步的解釋了其真正的價值。 函數

簡單來講序列化就是一種用來處理對象流的機制,所謂對象流也就是將對象的內容進行流化,流的概念這裏不用多說(就是I/O),咱們能夠對流化後的對象進行讀寫操做,也可將流化後的對象傳輸於網絡之間(注:要想將對象傳輸於網絡必須進行流化)!在對對象流進行讀寫操做時會引起一些問題,而序列化機制正是用來解決這些問題的!

問題的引出:

如上所述,讀寫對象會有什麼問題呢?好比:我要將對象寫入一個磁盤文件然後再將其讀出來會有什麼問題嗎?別急,其中一個最大的問題就是對象引用!舉個例子來講:假如我有兩個類,分別是A和B,B類中含有一個指向A類對象的引用,如今咱們對兩個類進行實例化{ A a = new A(); B b = new B(); },這時在內存中實際上分配了兩個空間,一個存儲對象a,一個存儲對象b,接下來咱們想將它們寫入到磁盤的一個文件中去,就在寫入文件時出現了問題!由於對象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類中的一個數據字段,並演示如何將其序列化!

import java.io.*;

import java.awt.geom.*;

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);
                         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
{
         public LabeledPoint(String str, double x, double y)
         {
                 label = str;
                 point = new Point2D.Double(x, y);
         }

         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);

         }

         public String toString()
         {
                 return getClass().getName()+ "[label = " + label+ ", point.getX() = " + point.getX()+ ", point.getY() = " + point.getY()+ "]";
         }
         private String label;
         transient private Point2D.Double point;
}轉自: http://blog.sina.com.cn/s/blog_5b142cae0100clon.html

總結:對象序列化,就是保證多處須要使用的對象,若是是同一個,就只實例化一次,這樣,效率高,若是對象發生了變化,只要序列化的對象流發生對應的變法便可。 spa

什麼狀況下使用: 代理

有兩個最重要的緣由促使對序列化的使用:一個緣由是將對象的狀態保持在存儲媒體中,以即可以在之後從新建立精確的副本;另外一個緣由是經過值將對象從一個應用程序域發送到另外一個應用程序域中。 xml

 參考:http://www.cnblogs.com/gaozhongfa/archive/2009/12/08/1619041.html htm

相關文章
相關標籤/搜索