Java對象序列化就那些實現了Serializable接口的對象轉換成一個字節序列,并能夠在以后將這個字節序列完全恢復為原來的對象。這一過程甚至可以通過網絡進行;運行Windows操作系統的計算機上創建的一個對象將其序列化,通過網絡將它發送到一臺運行Unix系統的計算機,然后在那里準確地重新組裝。Java序列化的一個引用就是RMI,當向遠程對象發送消息,需要通過對象序列化來傳輸參數和返回值。如下例所示:

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

public class Logon implements Serializable{
?private Date date=new Date();
?private String username;
?private transient String password; //加transient表示不進行序列化,所以輸出為(n/a)

?public Logon(String name,String pwd){
??username=name;
??password=pwd;
?}
?
?public String toString(){
??String pwd=(password==null)?"(n/a)":password;
??return "Long info: \n username: "+username+"\n date: "+date+"\n password: "+pwd;
?}
?
?public static void main(String[] args)throws Exception{
??Logon a=new Logon("Hulk","myLittleBoy");
??System.out.println("Logon a = "+a);
??ObjectOutputStream o= new ObjectOutputStream(new FileOutputStream("Logon.out"));?
??o.writeObject(a);
??o.close();
??Thread.sleep(3000);
??
??ObjectInputStream in= new ObjectInputStream(new FileInputStream("Logon.out"));
??System.out.println("Recovering object at "+new Date());
??a=(Logon)in.readObject();
??System.out.println("logon a="+a);
?}
}

編譯通過,運行結果如下:
Logon a = Long info:
?username: Hulk
?date: Fri Sep 22 17:13:28 CST 2006
?password: myLittleBoy
Recovering object at Fri Sep 22 17:13:31 CST 2006
logon a=Long info:
?username: Hulk
?date: Fri Sep 22 17:13:28 CST 2006
?password: (n/a)
a.dateFri Sep 22 17:13:28 CST 2006

從輸出結果可以看到,即對象被重新恢復。如果對象內包含了其他對象的引用,那么這些引用也會被保存并且被恢復出來,如上Date對象的引用date。
如果需要對序列化進行控制,可以實現Externalizable接口(代替實現Serializable接口)。這個Externalizable接口繼承了Serializable接口并且增加了兩個方法:writeExternal()和readExternal()。這兩個方法會在序列化和反序列化過程中被自動調用,以便執行一些特殊操作。如下所示:

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

public class Blip implements Externalizable{
?private int i;
?private String s;
?public Blip(){??//pulic標識符不能少
??System.out.println("Blip Constructor.");
?}
?
?public Blip(String x,int a){??
??System.out.println("Blip(String x,int a)");
??s=x;
??i=a;
?}
?public String toString(){return s +" "+i;};
?public void writeExternal(ObjectOutput out)
?throws IOException{
??System.out.println("Blip.writeExternal");
??out.writeObject(s);
??out.writeInt(i);
?}
?public void readExternal(ObjectInput in)
?throws IOException,ClassNotFoundException{
??System.out.println("Blip.readExternal");
??s=(String)in.readObject();
??i=in.readInt();
?}
?public static void main(String[] args)
?throws IOException,ClassNotFoundException{
???System.out.println("Constructing Object:");
???Blip b=new Blip("A String",47);
??? System.out.println(b);
???
??? ObjectOutputStream o= new ObjectOutputStream(new FileOutputStream("Blip.out"));
??? System.out.println("Saving Object:");
??? o.writeObject(b);
??? o.close();
???
??? ObjectInputStream in= new ObjectInputStream(new FileInputStream("Blip.out"));
??? System.out.println("Recovering b:");
??? b=(Blip)in.readObject();
???System.out.println(b);
?}
}

運行結果如下:
Constructing Object:
Blip(String x,int a)
A String 47
Saving Object:
Blip.writeExternal
Recovering b:
Blip Constructor.
Blip.readExternal
A String 47

從運行結果可以看到,由于我們的恢復和存儲功能由writeExternal()和readExternal()完成,所以修改writeExternal()和readExternal()方法就可以控制序列化了。從結果還可以看到,恢復b后,會調用Blip缺省構造器,這個時候缺省構造器須是public的,否則運行時會拋出異常(能通過編譯):
Exception in thread "main" java.io.InvalidClassException: Blip; no valid constructor。
當然也不能利用類提供的缺省構造器,因為類提供的構造起沒有任何標識符的,所以就不是public的。所以必須寫一個public的缺省構造器。