Java對(duì)象序列化就那些實(shí)現(xiàn)了Serializable接口的對(duì)象轉(zhuǎn)換成一個(gè)字節(jié)序列,并能夠在以后將這個(gè)字節(jié)序列完全恢復(fù)為原來(lái)的對(duì)象。這一過(guò)程甚至可以通過(guò)網(wǎng)絡(luò)進(jìn)行;運(yùn)行Windows操作系統(tǒng)的計(jì)算機(jī)上創(chuàng)建的一個(gè)對(duì)象將其序列化,通過(guò)網(wǎng)絡(luò)將它發(fā)送到一臺(tái)運(yùn)行Unix系統(tǒng)的計(jì)算機(jī),然后在那里準(zhǔn)確地重新組裝。Java序列化的一個(gè)引用就是RMI,當(dāng)向遠(yuǎn)程對(duì)象發(fā)送消息,需要通過(guò)對(duì)象序列化來(lái)傳輸參數(shù)和返回值。如下例所示:
import java.io.*;
import java.util.*;
public class Logon implements Serializable{
?private Date date=new Date();
?private String username;
?private transient String password; //加transient表示不進(jìn)行序列化,所以輸出為(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);
?}
}
編譯通過(guò),運(yùn)行結(jié)果如下:
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
從輸出結(jié)果可以看到,即對(duì)象被重新恢復(fù)。如果對(duì)象內(nèi)包含了其他對(duì)象的引用,那么這些引用也會(huì)被保存并且被恢復(fù)出來(lái),如上Date對(duì)象的引用date。
如果需要對(duì)序列化進(jìn)行控制,可以實(shí)現(xiàn)Externalizable接口(代替實(shí)現(xiàn)Serializable接口)。這個(gè)Externalizable接口繼承了Serializable接口并且增加了兩個(gè)方法:writeExternal()和readExternal()。這兩個(gè)方法會(huì)在序列化和反序列化過(guò)程中被自動(dòng)調(diào)用,以便執(zhí)行一些特殊操作。如下所示:
import java.io.*;
import java.util.*;
public class Blip implements Externalizable{
?private int i;
?private String s;
?public Blip(){??//pulic標(biāo)識(shí)符不能少
??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);
?}
}
運(yùn)行結(jié)果如下:
Constructing Object:
Blip(String x,int a)
A String 47
Saving Object:
Blip.writeExternal
Recovering b:
Blip Constructor.
Blip.readExternal
A String 47
從運(yùn)行結(jié)果可以看到,由于我們的恢復(fù)和存儲(chǔ)功能由writeExternal()和readExternal()完成,所以修改writeExternal()和readExternal()方法就可以控制序列化了。從結(jié)果還可以看到,恢復(fù)b后,會(huì)調(diào)用Blip缺省構(gòu)造器,這個(gè)時(shí)候缺省構(gòu)造器須是public的,否則運(yùn)行時(shí)會(huì)拋出異常(能通過(guò)編譯):
Exception in thread "main" java.io.InvalidClassException: Blip; no valid constructor。
當(dāng)然也不能利用類(lèi)提供的缺省構(gòu)造器,因?yàn)轭?lèi)提供的構(gòu)造起沒(méi)有任何標(biāo)識(shí)符的,所以就不是public的。所以必須寫(xiě)一個(gè)public的缺省構(gòu)造器。