對象序列化可以將任何對象寫出到流中,并在之后將其讀回
要序列化的對象的類必須實現 Serializable
接口,Serializable接口沒有任何方法
序列化的一個重要作用是通過網絡將對象傳送到另一臺計算機,因為序列化用序列號代替內存地址,每個對象都有一個序列號
類中靜態成員不會被序列化,因為靜態成員屬于類級別,序列化只是序列化對象,所以序列化寫入的只有非瞬態
和非靜態
數據域
讀取對象的順序與寫入時的順序
要一致
某些數據域不想或不能被序列化,用 transient (瞬態)
標記,如:
序列化和反序列化中需要特殊處理的行為可以使用下列簽名的方法(對某些數據域)
private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException;private void writeObject(ObjectOutputStream out) throws IOException;//例子public class LabelPoint implements Serializable{ private String label; private transient Point2D.Double point; ... 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(); double y = in.readDouble(); point = new Point2D.Double(x,y); }}readObject和writeObject方法不關心超類數據和其他類的信息。readExternal和writeExternal方法對包括超類數據在內的整個對象的存儲和恢復負責(接口不一樣)
public class Foo implements Externalizable{ private int a; private String b; private Date c; public void readExternal(ObjectInputStream in) throws IOException { a = in.readInt(); b = in.readString(); c = new Date(in.readLong()); } public void writeExternal(ObjectOutputStream out) throws IOException { out.writeInt(a); out.writeString(b); out.writeLong(c.getTime()); }}類型安全的枚舉和單例模式的類需要添加readResolve方法
,因為此時默認的序列化機制不起作用。
readResolve方法在對象被序列化之后被調用,必須返回一個對象,此對象會成為之后readObject方法的返回值,如:
class Foo implements Serializable{ public static final Foo TEST1=new Foo(1); public static final Foo TEST2=new Foo(2); private int value; private Foo(int v){value=v;}}//TEST1是單例Foo original = Foo.TEST1;ObjectOutputStream out = ...out.writeObject(foo1);out.close();//此時saved和original不是同一個對象,errorObjectInputStream in = ...Foo saved = (Foo)in.readObject();//Foo類中添加readResolveprotected Object readResolve() throws ObjectStreamException{ if(value==1) return Foo.TEST1; if(value==2) return Foo.TEST2; return null; //這一步不應該發生}類可以對其早期版本進行兼容,但必須有這個類早期版本的指紋,即 serialVersionUID
,此靜態數據成員被放在某個類,則序列化系統就可以讀入這個類的對象的不同版本(這個類的所有較新版本都必須把 serialVersionUID 定義為與初始版本相同)
如果這個類只有方法發生了變化,則讀入新對象數據時不會有問題;如果數據域發生了變化,則可能有問題,對象流將盡力將流對象轉換成這個類的當前版本,做法如下(不處理瞬態和靜態數據域):
對于數據域名字匹配,類型不匹配,不會轉換流中對象具有當前版本沒有的數據域,則忽略這些數據域當前版本具有流對象中沒有的數據域,則這些新添加的數據域設置成他們的默認值,對象為null,數字為0,boolean為false新聞熱點
疑難解答