1. 程式人生 > >YYlxid————Nothing is possible if not try~

YYlxid————Nothing is possible if not try~

一個物件只要實現了Serializable介面,該物件就可以被序列化。然而在實際開發過程中,常常會遇到這樣的問題,該類有些屬性需要序列化,其他屬性不需要被序列化。例如一個使用者有一些敏感資訊(如密碼,銀行卡號等),為了安全起見,不希望在網路操作(主要涉及序列化)中被傳輸,這些資訊對應的變數就可以加上transient關鍵字,這樣變數的生命週期僅存在於呼叫者的記憶體中而不會被寫到磁盤裡持久化。

序列化與反序列化

持久化物件、RMI(遠端方法呼叫)、在網路中傳遞物件時,會用到物件序列化。在序列化物件時,不僅會序列化當前物件本身,還會對該物件引用的其他物件也進行序列化。

序列化:把物件轉換為位元組序列的過程

反序列化:把位元組序列恢復為物件的過程

java中只要實現了Serializable、Externalizable介面的類的物件就可被序列化。

實現Java物件序列化與反序列化的方法

方法一:若類僅僅實現了Serializable介面,則可以按照以下方式進行序列化和反序列化

ObjectOutputStream採用預設的序列化方式,將物件的非transient的例項變數進行序列化。

ObjcetInputStream採用預設的反序列化方式,將物件的非transient的例項變數進行反序列化。

方法二:若類僅僅實現了Serializable介面,並且還定義了readObject(ObjectInputStreamin)和writeObject(ObjectOutputSteam out),則採用以下方式進行序列化與反序列化。

ObjectOutputStream呼叫物件的writeObject(ObjectOutputStreamout)的方法進行序列化。

ObjectInputStream會呼叫物件的readObject(ObjectInputStreamin)的方法進行反序列化。

方法三:若類實現了Externalnalizable介面,且類必須實現readExternal(ObjectInputin)和writeExternal(ObjectOutput out)方法,則按照以下方式進行序列化與反序列化。

ObjectOutputStream呼叫物件的writeExternal(ObjectOutput out))的方法進行序列化。

ObjectInputStream會呼叫物件的readExternal(ObjectInput in)的方法進行反序列化。

物件序列化和反序列化例項(方法一)+transient關鍵字:

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
 
/**   
 * @Title: SerializableTest.java 
 * @author olive  
 * @date Feb 19, 2016 9:28:30 AM  
 * 序列化: 把物件轉換為位元組序列的過程
 * 反序列化: 把位元組序列恢復為物件的過程
 */
public class SerializableTest implements Serializable{
    /**
     * serializable ID
     */
    private static final long serialVersionUID = -7873944822450384597L;
    private String username;
    private transient String psw;
    public SerializableTest(String username,String psw){
        this.username=username;
        this.psw=psw;
    }
     
    /**
     * @return the username
     */
    public String getUsername() {
        return username;
    }
 
    /**
     * @param username the username to set
     */
    public void setUsername(String username) {
        this.username = username;
    }
 
    /**
     * @return the psw
     */
    public String getPsw() {
        return psw;
    }
 
    /**
     * @param psw the psw to set
     */
    public void setPsw(String psw) {
        this.psw = psw;
    }
    public static void main(String[]args){
        SerializableTest a=new SerializableTest("mary","12345");
        String file="D:\\tmp.txt";
        try {
            System.out.println("username:"+a.getUsername()+" password:"+a.getPsw());
            // 使用ObjectOutputStream將物件SerializableTest序列化,並將其儲存到檔案中
            FileOutputStream fos=new FileOutputStream(file);
            ObjectOutputStream out=new ObjectOutputStream(fos);
            out.writeObject(a);
            out.flush();
            out.close();
            fos.close();
            // 使用ObjectInputStream將物件反序列化
            ObjectInputStream in=new ObjectInputStream(new FileInputStream("D:\\tmp.txt"));
            SerializableTest test=(SerializableTest)in.readObject();
            System.out.println("username:"+test.getUsername()+" password:"+test.getPsw());
            in.close();
        } catch (FileNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
}


輸出:

1

2

3

username:mary password:12345

username:mary password:null

密碼為null,說明反序列化沒有從檔案中得到該資訊。

Java的序列化機制是通過在執行時判斷類的serialVersionUID來驗證版本一致性的。在進行反序列化時,JVM會把傳來的位元組流中的serialVersionUID與本地相應實體(類)的serialVersionUID進行比較,如果相同就認為是一致的,可以進行反序列化,否則就會出現序列化版本不一致的異常。(InvalidCastException)

參考: