Java 对象序列化主要用到了下面两个类:
ObjectOutputStream
ObjectInputStream
Java 提供了了默认的自动对象序列化机制,只需要实现Serializable接口就可以了。Serializable是一个空接口,里面没有任何方法。下面简单的看一个例子:
import java.io.IOException;
程序运行结果为:import java.io.ObjectInputStream;import java.io.ObjectOutputStream;import java.io.Serializable;public class Demo implements Serializable{private static final long serialVersionUID = 1L;String s;public Demo(String str){s = str;}public static void main(String[] args) throws FileNotFoundException, IOException, ClassNotFoundException {String name = "Demo.out";ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(name));Demo d = new Demo("Demo");System.out.println("1:"+d.s);oos.writeObject(d);ObjectInputStream ois = new ObjectInputStream(new FileInputStream(name));Demo demo = (Demo) ois.readObject();System.out.println("2:"+d.s);}}
1:Demo
2:Demo
2:Demo
正如大家所看到的默认的对象序列化机制相当简单。Java同时还提供了另外一种机制,可以手动来对序列化过程进行控制。
这种方法需要实现Externalizable接口。
public interface Externalizable extends java.io.Serializable {void writeExternal(ObjectOutput out) throws IOException;void readExternal(ObjectInput in) throws IOException, ClassNotFoundException;}
Externalizable接口继承于Serializable接口,同时增加了两个方法writeExternal()和readExternal()。这两个方法会在对象的序列化和反序列化的过程中被自动调用,以便执行一些特殊操作。
import java.io.Externalizable;
import java.io.FileInputStream;import java.io.FileNotFoundException;import java.io.FileOutputStream;import java.io.IOException;import java.io.ObjectInput;import java.io.ObjectInputStream;import java.io.ObjectOutput;import java.io.ObjectOutputStream;class Blip1 implements Externalizable {public Blip1() {Blip.print("Blip1 Construct");}@Overridepublic void writeExternal(ObjectOutput out) throws IOException {Blip.print("Blip1 writeExternal");}@Overridepublic void readExternal(ObjectInput in) throws IOException,ClassNotFoundException {Blip.print("Blip2 readExternal");}}class Blip2 implements Externalizable {Blip2() {Blip.print("Blip2 Construct");}@Overridepublic void writeExternal(ObjectOutput out) throws IOException {Blip.print("Blip2 writeExternal");}@Overridepublic void readExternal(ObjectInput in) throws IOException,ClassNotFoundException {Blip.print("Blip2 readExternal");}}public class Blip{static void print(String s) {System.out.println(s);}public static void main(String[] args) throws FileNotFoundException, IOException, ClassNotFoundException {print("Constructing objects");Blip1 b1 = new Blip1();Blip2 b2 = new Blip2();print(b1+":"+b2);String file = "Blip.out";ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(file ));print("Saving object");out.writeObject(b1);out.writeObject(b2);out.close();ObjectInputStream in = new ObjectInputStream(new FileInputStream(file));print("Recovering b1:");b1 = (Blip1) in.readObject();print("Recovering b2:");b2 = (Blip2) in.readObject();print(b1+":"+b2);}}这段代码的运行结果为:Constructing objectsBlip1 ConstructBlip2 Constructcom.leo.io.Blip1@1fb8ee3:com.leo.io.Blip2@61de33Saving objectBlip1 writeExternalBlip2 writeExternalRecovering b1:Blip1 ConstructBlip2 readExternalRecovering b2:Exception in thread "main" java.io.InvalidClassException: com.leo.io.Blip2; com.leo.io.Blip2; no valid constructorat java.io.ObjectStreamClass.checkDeserialize(Unknown Source)at java.io.ObjectInputStream.readOrdinaryObject(Unknown Source)at java.io.ObjectInputStream.readObject0(Unknown Source)at java.io.ObjectInputStream.readObject(Unknown Source)at com.leo.io.Blip.main(Blip.java:72)Caused by: java.io.InvalidClassException: com.leo.io.Blip2; no valid constructorat java.io.ObjectStreamClass.<init>(Unknown Source)at java.io.ObjectStreamClass.lookup(Unknown Source)at java.io.ObjectOutputStream.writeObject0(Unknown Source)at java.io.ObjectOutputStream.writeObject(Unknown Source)at com.leo.io.Blip.main(Blip.java:65)为什么会报错呢?大家仔细看代码会发现Blip1 和 Blip2 的默认构造函数有所区别,把Blip2的构造函数改为:
public Blip2() {
Blip.print("Blip2 Construct");
}
然后运行,结果为:
Constructing objects
Blip1 Construct
Blip2 Construct
com.leo.io.Blip1@1fb8ee3:com.leo.io.Blip2@61de33
Saving object
Blip1 writeExternal
Blip2 writeExternal
Recovering b1:
Blip1 Construct
Blip2 readExternal
Recovering b2:
Blip2 Construct
Blip2 readExternal
com.leo.io.Blip1@69b332:com.leo.io.Blip2@173a10f
由此我们可以看出:对于Serializable对象,对象完全以它存储的二进制位为基础来构造。而不调用构造器;对于Externalizable 对象,默认构造器在readExternal()里会被调用。所以Externalizable 必须提供一个默认构造器。一般都是在writeExternal()里将需要的信息写入,在readExternal()恢复数据。
下面的这个例子示范了如何完整保存和恢复一个Externalizable 对象
import java.io.Externalizable;
import java.io.FileInputStream;import java.io.FileNotFoundException;import java.io.FileOutputStream;import java.io.IOException;import java.io.ObjectInput;import java.io.ObjectInputStream;import java.io.ObjectOutput;import java.io.ObjectOutputStream;public class Blip3 implements Externalizable {private int i;private String s;public Blip3(){print("Blip3 default construct");}public Blip3(String x, int a){print("Blip3(String "+ x+ ", int" + a +")");s = x;i = a;}@Overridepublic String toString() {return s + i;}static void print(String s) {System.out.println(s);}@Overridepublic void writeExternal(ObjectOutput out) throws IOException {print("Blip3 writeExternal");out.writeObject(s);out.writeInt(i);}@Overridepublic void readExternal(ObjectInput in) throws IOException,ClassNotFoundException {print("Blip3 readExternal");s = (String) in.readObject();i = in.readInt();}public static void main(String[] args) throws FileNotFoundException, IOException, ClassNotFoundException {Blip3 b3 = new Blip3("A", 47);print(b3.toString());String name = "Blip3.out";ObjectOutputStream o = new ObjectOutputStream(new FileOutputStream(name));o.writeObject(b3);o.close();ObjectInputStream in = new ObjectInputStream(new FileInputStream(name));b3 = (Blip3) in.readObject();print(b3.toString());}}运行结果:Blip3(String A, int47)A47Blip3 writeExternalBlip3 default constructBlip3 readExternalA47