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的缺省构造器。