一個對象只要實現了Serializable接口,該對象就可以被序列化。然而在實際開發過程中,常常會遇到這樣的問題,該類有些屬性需要序列化,其他屬性不需要被序列化。例如一個用戶有一些敏感信息(如密碼,銀行卡號等),為了安全起見,不希望在網絡操作(主要涉及序列化)中被傳輸,這些信息對應的變量就可以加上transient關鍵字,這樣變量的生命周期僅存在於調用者的內存中而不會被寫到磁盤里持久化。
序列化與反序列化
持久化對象、RMI(遠程方法調用)、在網絡中傳遞對象時,會用到對象序列化。在序列化對象時,不僅會序列化當前對象本身,還會對該對象引用的其他對象也進行序列化。
序列化:把對象轉換為字節序列的過程
反序列化:把字節序列恢復為對象的過程
java中只要實現了Serializable、Externalizable接口的類的對象就可被序列化。
實現Java對象序列化與反序列化的方法
方法一:若類僅僅實現了Serializable接口,則可以按照以下方式進行序列化和反序列化
ObjectOutputStream采用默認的序列化方式,將對象的非transient的實例變量進行序列化。
ObjcetInputStream采用默認的反序列化方式,將對象的非transient的實例變量進行反序列化。
方法二:若類僅僅實現了Serializable接口,並且還定義了readObject(ObjectInputStream in)和writeObject(ObjectOutputSteam out),則采用以下方式進行序列化與反序列化。
ObjectOutputStream調用對象的writeObject(ObjectOutputStream out)的方法進行序列化。
ObjectInputStream會調用對象的readObject(ObjectInputStream in)的方法進行反序列化。
方法三:若類實現了Externalnalizable接口,且類必須實現readExternal(ObjectInput in)和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(); } } } |
輸出:
|
|
密碼為null,說明反序列化沒有從文件中得到該信息。
Java的序列化機制是通過在運行時判斷類的serialVersionUID來驗證版本一致性的。在進行反序列化時,JVM會把傳來的字節流中的serialVersionUID與本地相應實體(類)的serialVersionUID進行比較,如果相同就認為是一致的,可以進行反序列化,否則就會出現序列化版本不一致的異常。(InvalidCastException)
參考:
http://www.cnblogs.com/lanxuezaipiao/p/3369962.html
http://blog.csdn.net/wangloveall/article/details/7992448
http://www.cnblogs.com/xdp-gacl/p/3777987.html
http://developer.51cto.com/art/201202/317181.htm
http://www.cnblogs.com/guanghuiqq/archive/2012/07/18/2597036.html
