1.序列化/反序列化一个未实现序列化接口的类型对象
如果这个类(称其为A类)提供了带参数的构造器,那么可以创建一个实现了序列化接口的新类(称其为B类)。B类中用属性来持有创建A类对象所需要的那些参数。这样问题就从序列化/反序列化一个A类对象转为了序列化/反序列化创建一个A类对象所需要的参数。
示例代码如下:
- public class A {
- private String name;
- private int age;
-
- public A(int age, String name) {
- this.age = age;
- this.name = name;
- }
-
- public int getAge() {
- return age;
- }
-
- public String getName() {
- return name;
- }
-
- @Override
- public String toString() {
- return "A{" +
- "age=" + age +
- ", name='" + name +'\'' +
- '}';
- }
- }
A类没有实现序列化接口。
设计一个B类“持有”一个A类,并且实现了序列化接口。当需要序列化一个A类对象的时候,可以通过一个序列化一个B对象,来序列化A对象的属性内容。
- public class B implements Serializable{
- private String name;
- private int age;
- private A a;
-
- public B(String name, int age) {
- this.name = name;
- this.age = age;
- }
- private void writeObject(ObjectOutputStream out) throws IOException{
- out.writeUTF(name);
- out.writeInt(age);
- }
- private voidreadObject(ObjectInputStream in)
- throwsIOException,ClassNotFoundException{
- name = in.readUTF();
- age = in.readInt();
- a = new A(age,name);
- }
- public String toString() {
- return "B{a= " + a + ", name='" + name + '\'' +", age=" + age + '}';
- }
- public A getA(){
- return new A(age,name);
- }
- }
这里需要注意的是B类里面有两个“特殊”的方法writeObject(ObjectOutputStream)和readObject(ObjectInputStream),当进行序列化/反序列化操作的时候,如果Java发现要序列化/反序列化的对象包含这样两个方法,则会优先使用这两个方法进行序列化/反序列化操作。即序列化B对象的时候,会调用B类的writeObject方法来进行而不使用ObjectOutputStream的writeObject方法。反序列化B对象的时候,会调用B类的readObject方法来进行而不使用ObjectInputStream的readObject方法。另外,通过ObjectOutputStream和ObjectInputStream包含的writeXXX方法和readXXX方法,可以知道尽管ObjectOutputStream继承自OutputStream,但是它的行为方式却是FilterOutputStream,ObjectInputStream也是这样的。而且与DataOutputStream/DataInputStream更加类似的是,反序列化时的读取属性顺序要与序列化时的存储属性顺序和方式一致。
下面是使用B类对象来间接序列化/反序列化A类对象的代码示例:
- public class ObjectStreamTest {
- public static void main(String[] args) throws Exception {
- ObjectOutputStream out =
- new ObjectOutputStream(new FileOutputStream("d:/test.dat"));
- A a = new A(29,"Tony");
- B b = new B(a.getName(),a.getAge());
- out.writeObject(b);
- out.close();
- out = null;
- System.out.println("序列化完毕");
- ObjectInputStream in = new ObjectInputStream(new FileInputStream("d:/test.dat"));
- B bb = (B) in.readObject();
- System.out.println(bb);
- System.out.println(bb.getA());
- in.close();
- }
- }
2.外部化 Externalization
可以把外部化看做一种自定义式的序列化操作。一个类实现了Externalizable接口就意味着这个类的对象是外部化的。Externalizable接口中有两个抽象方法writeExternal和readExternal,分别用来序列化和反序列化一个可外部化的对象时被调用。
下面是外部化类对象的使用示例:
- public class A implements Externalizable{
- private String name;
- private int age;
- public A() {
- }
- public A(int age, String name) {
- this.name = name;
- this.age = age;
- }
- public int getAge() {
- return age;
- }
- public String getName() {
- return name;
- }
- @Override
- public String toString() {
- return "A{" +
- "age=" + age +
- ", name='" + name +'\'' +
- '}';
- }
- @Override
- public void writeExternal(ObjectOutput out) throws IOException {
- System.out.println("writeExternal方法被调用了");
- out.writeUTF(name);
- out.writeInt(age);
- }
- @Override
- public void readExternal(ObjectInput in) throws IOException,ClassNotFoundException {
- System.out.println("readExternal方法被调用了");
- name = in.readUTF();
- age = in.readInt();
- }
- }
写一个测试类,序列化/反序列化一个A类对象:
- public class ObjectStreamTest2 {
- public static void main(String[] args) throws IOException,ClassNotFoundException {
- System.out.println("测试外部化");
- A a = new A(30,"Tom");
- ObjectOutputStream out =
- new ObjectOutputStream(new FileOutputStream("d:/obj.dat"));
- out.writeObject(a);
- out.close();
- out = null;
- System.out.println("对象序列化完毕");
- ObjectInputStream in =
- new ObjectInputStream(new FileInputStream("d:/obj.dat"));
- A aa = (A) in.readObject();
- in.close();
- System.out.println("对象反序列化完毕"+aa);
- }
- }
执行结果下所示:
测试外部化
- writeExternal方法被调用了
- 对象序列化完毕
- readExternal方法被调用了
- 对象反序列化完毕A{age=30,name='Tom'}
可见我们在使用ObjectOutputStream/ObjectInputStream序列化和反序列化对象的时候,虽然表面上都是通过writeObject/readObject方法来执行,但是执行的内容确不一样:
1)如果序列化/反序列化对象实现了外部化接口,则writeObject调用对象的writeEnternal方法,readObject调用对象的readExternal方法。
2)如果对象实现的是Serializable接口,但是对象有自己的writeObject和readObject方法,则ObjectOutputStream的writeObject方法会去调用对象自己的writeObject方法,ObjectInputStream的readObject方法会去调用对象自己的readObject方法。
3)如果对象实现的是Serializable接口,但是没有自己的writeObject和readObject方法,则ObjectOutputStream的writeObject方法和ObjectInputStream的readObject方法会执行默认的操作。