讀書筆記:淺談Java的序列化

之前看過一遍《Java編程思想》,把書中的代碼理解了一遍,也都敲過一遍。但是很多比較深入的知識在實際的工作中并未使用到,因此都忘記了,為了給自己做一些鞏固,在以后的時間里,我會努力地做一些關于這些內容的讀書筆記,以加強自己的理解
Java的序列化是指將Java對象轉化為可在磁盤或者其它存儲介質中保存的字節序列,以便在后續的操作中將這個字節序列重新復原為Java對象,存儲的字節序列可以寫入文件亦可以通過網絡進行傳輸。那么什么對象可以被序列化呢?被序列化的對象必須實現Serializable接口,請看下例:

package com.fan;

import java.io.*;
import java.util.Random;

/**
 * Created by Alpha on 17/4/16.
 */
class Data implements Serializable {
    private int n;
    public Data(int n){this.n = n;}
    public String toString(){return Integer.toString(n);}
}

public class Worm implements Serializable{
    private static Random rand = new Random(47);
    private Data d[] = {
            new Data(rand.nextInt(10)),
            new Data(rand.nextInt(10)),
            new Data(rand.nextInt(10))
    };

    private Worm next;
    private char c;

    public Worm(int i,char x){
        System.out.println("Worm constructor:" + i);
        c = x;
        if(--i > 0){
            next = new Worm(i,(char)(x + 1));
        }
    }

    public Worm(){
        System.out.println("Default constructor");
    }
    public String toString(){
        StringBuilder result = new StringBuilder(":");
        result.append(c);
        result.append("(");
        for(Data dat : d)
            result.append(dat);
        result.append(")");
        if(next != null)
            result.append(next);
        return result.toString();
    }

    public static void test() throws IOException, ClassNotFoundException {
        Worm w = new Worm(6,'a');
        System.out.println("w = " + w);
        ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("worm.out"));
        out.writeObject("Worm storage");
        out.writeObject(w);
        out.close();
        ObjectInputStream in = new ObjectInputStream(new FileInputStream("worm.out"));
        String s = (String) in.readObject();
        Worm w2 = (Worm) in.readObject();
        System.out.println(s + "w2 = " + w2);
        ByteArrayOutputStream bout = new ByteArrayOutputStream();
        ObjectOutputStream out2 = new ObjectOutputStream(bout);
        out2.writeObject("worm storage");
        out2.writeObject(w);
        out2.flush();
        ObjectInputStream in2 = new ObjectInputStream(new ByteArrayInputStream(bout.toByteArray()));
        s = (String) in2.readObject();
        Worm w3 = (Worm) in2.readObject();
        System.out.println(s + "w3 = " + w3);
    }
}

輸出如下:

在上面的例子中我們可以看到,我們定義了兩個類,DataWorm,它們都實現了Serializable接口,在測試方法中我們創建一個包含6個Worm類對象并將這些對象寫到了文件worm.out中,看上面的讀取步驟,與寫入的步驟相同,我們也是先讀取一個字符串對象再讀取一個Worm對象

如上例,假如我們將寫的對象的序列化文件通過網絡傳輸給其它的計算機,那么其它的計算機是不是同樣也能解析出這個對象呢,答案是不一定,假如另一臺計算機中的classpath中沒有上述的Data類和Worm類,那么就會拋出一個ClassNotFoundException的異常

Externalizable

假如我們需要序列化一個對象,但是又不希望將這個對象的所有成員都序列化,比如登錄表單,我們只希望提供給用戶用戶名而不是密碼,那么我們可以將包含用戶名密碼的類通過實現Externalizable接口來實現,請看下面的實例

package com.fan;

import java.io.*;

/**
 * Created by Alpha on 17/4/16.
 */
public class Blips3 implements Externalizable {
    private int i;
    private String s;
    public  Blips3(){
        System.out.println("Blips3 constructor");
    }

    public Blips3(String x,int a){
        s = x;
        i = a;
    }
    public String toString(){return s + i;}
    @Override
    public void writeExternal(ObjectOutput out) throws IOException {
        System.out.println("Blips3.writeExternal");
        out.writeObject(s);
        out.writeInt(i);
    }

    @Override
    public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
        System.out.println("Blips3.readExternal");
        s = (String) in.readObject();
        i = in.readInt();
    }

    public static void test() throws IOException, ClassNotFoundException {
        System.out.println("Constructing objects:");
        Blips3 b3 = new Blips3("A String " , 47);
        System.out.println(b3);
        ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("Blip3.out"));
        System.out.println("Saving object:");
        out.writeObject(b3);
        out.close();
        ObjectInputStream in = new ObjectInputStream(new FileInputStream("Blip3.out"));
        System.out.println("Recovering b3:");
        b3 = (Blips3) in.readObject();
        System.out.println(b3);
    }
}

輸出如下


如上,我們在使用Externalizable接口來進行對象的初始化時,我們必須實現Externalizable類的兩個接口writeExternalreadExternal,這個過程和Serializable接口的不太一樣,Serializable是以二進制為基礎來對對象進行存儲,而Externalizable則需要調用構造器,寫入時調用writeExternal,讀取時調用readExternal,因此我們假如我們不想某個成員的內容被序列化,我們可以不在writeExternal方法里將其寫入輸出文件。注意在使用序列化寫入或讀取時,寫入的方法和讀取的對應的方法要一致

transient關鍵字

利用Serializable也可以實現對象的部分成員序列化,那就是對不需要序列化的成員使用transient關鍵字,如下例所示

package com.fan;

import java.io.*;
import java.util.Date;
import java.util.concurrent.TimeUnit;

/**
 * Created by fanwenlong on 17/4/16.
 */
public class Logon implements Serializable {
    private Date date = new Date();
    private String username;
    private transient String password;
    public Logon(String username,String password){
        this.username = username;
        this.password = password;
    }
    public String toString(){
        return "logon info:\n username:" + username + "\n date:" + date + "\n password:" + password;
    }
    public static void test() throws IOException, InterruptedException, ClassNotFoundException {
        Logon logon = new Logon("Aplha","hello");
        System.out.println("Logon logon = " + logon);
        ObjectOutputStream o = new ObjectOutputStream(new FileOutputStream("Logon.out"));
        o.writeObject(logon);
        o.close();
        TimeUnit.SECONDS.sleep(1);
        ObjectInputStream in = new ObjectInputStream(new FileInputStream("Logon.out"));
        System.out.println("Recoving object at:" + new Date());
        logon = (Logon) in.readObject();
        System.out.println("logon logon = " + logon);
    }
}

結果如下


可以看到,上面的password寫入序列化后再次的值為空,說明其沒有被寫入保存

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • JAVA序列化機制的深入研究 對象序列化的最主要的用處就是在傳遞,和保存對象(object)的時候,保證對象的完整...
    時待吾閱讀 10,913評論 0 24
  • 一、 序列化和反序列化概念 Serialization(序列化)是一種將對象以一連串的字節描述的過程;反序列化de...
    步積閱讀 1,457評論 0 10
  • 官方文檔理解 要使類的成員變量可以序列化和反序列化,必須實現Serializable接口。任何可序列化類的子類都是...
    獅_子歌歌閱讀 2,440評論 1 3
  • 有人的地方就有江湖,有江湖的地方就有矛盾!任何組織里難能幸勉,黨派、團體、社群、協會、家庭……但任何矛盾最終升級成...
    黃健歌閱讀 617評論 3 2
  • 王梓亦用身體堵著門,她因為激動,身體劇烈的顫抖著。她的腳下是打碎的盤子、散落的衣服,好像整個屋子里的東西全部跑出來...
    許一帆閱讀 366評論 10 1