Java对象序列化深入理解(4)

必须注意地是,writeObject()与readObject()都是private方法,那么它们是如何被调用的呢?毫无疑问,是使用反射。详情可见ObjectOutputStream中的writeSerialData方法,以及ObjectInputStream中的readSerialData方法。

5.3 Externalizable接口
    无论是使用transient关键字,还是使用writeObject()和readObject()方法,其实都是基于Serializable接口的序列化。JDK中提供了另一个序列化接口--Externalizable,使用该接口之后,之前基于Serializable接口的序列化机制就将失效。此时将Person类修改成如下,

public class Person implements Externalizable {

   
private String name = null;

   
transient private Integer age = null;

   
private Gender gender = null;

   
public Person() {
        System.out.println(
"none-arg constructor");
    }

   
public Person(String name, Integer age, Gender gender) {
        System.out.println(
"arg constructor");
       
this.name = name;
       
this.age = age;
       
this.gender = gender;
    }

   
private void writeObject(ObjectOutputStream out) throws IOException {
        out.defaultWriteObject();
        out.writeInt(age);
    }

   
private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
        in.defaultReadObject();
        age 
= in.readInt();
    }

    @Override
   
public void writeExternal(ObjectOutput out) throws IOException {

    }

    @Override
   
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {

    }
   
}

此时再执行SimpleSerial程序之后会得到如下结果:

arg constructor
none
-arg constructor
[
nullnullnull]

从该结果,一方面可以看出Person对象中任何一个字段都没有被序列化。另一方面,如果细心的话,还可以发现这此次序列化过程调用了Person类的无参构造器。
    Externalizable继承于Serializable,当使用该接口时,序列化的细节需要由程序员去完成。如上所示的代码,由于writeExternal()与readExternal()方法未作任何处理,那么该序列化行为将不会保存/读取任何一个字段。这也就是为什么输出结果中所有字段的值均为空。
    另外,若使用Externalizable进行序列化,当读取对象时,会调用被序列化类的无参构造器去创建一个新的对象,然后再将被保存对象的字段的值分别填充到新对象中。这就是为什么在此次序列化过程中Person类的无参构造器会被调用。由于这个原因,实现Externalizable接口的类必须要提供一个无参的构造器,且它的访问权限为public。
    对上述Person类作进一步的修改,使其能够对name与age字段进行序列化,但要忽略掉gender字段,如下代码所示:

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/91d3cded3bd2896734f77403b79c8111.html