理解Java对象序列化(四)

2014-11-24 07:17:23 · 作者: · 浏览: 3
Externalizable继承于Serializable,当使用该接口时,序列化的细节需要由程序员去完成。如上所示的代码,由于writeExternal()与readExternal()方法未作任何处理,那么该序列化行为将不会保存/读取任何一个字段。这也就是为什么输出结果中所有字段的值均为空。
另外,若使用Externalizable进行序列化,当读取对象时,会调用被序列化类的无参构造器去创建一个新的对象,然后再将被保存对象的字段的值分别填充到新对象中。这就是为什么在此次序列化过程中Person类的无参构造器会被调用。由于这个原因,实现Externalizable接口的类必须要提供一个无参的构造器,且它的访问权限为public。
对上述Person类作进一步的修改,使其能够对name与age字段进行序列化,但要忽略掉gender字段,如下代码所示:
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 {
out.writeObject(name);
out.writeInt(age);
}

@Override
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
name = (String) in.readObject();
age = in.readInt();
}

}执行SimpleSerial之后会有如下结果:
arg constructor
none-arg constructor
[John, 31, null]
5.4 readResolve()方法
当我们使用Singleton模式时,应该是期望某个类的实例应该是唯一的,但如果该类是可序列化的,那么情况可能会略有不同。此时对第2节使用的Person类进行修改,使其实现Singleton模式,如下所示:
public class Person implements Serializable {

private static class InstanceHolder {
private static final Person instatnce = new Person("John", 31, Gender.MALE);
}

public static Person getInstance() {
return InstanceHolder.instatnce;
}

private String name = null;

private Integer age = null;

private Gender gender = null;

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

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

}同时要修改SimpleSerial应用,使得能够保存/获取上述单例对象,并进行对象相等性比较,如下代码所示:
public class SimpleSerial {

public static void main(String[] args) throws Exception {
File file = new File("person.out");
ObjectOutputStream oout = new ObjectOutputStream(new FileOutputStream(file));
oout.writeObject(Person.getInstance()); // 保存单例对象
oout.close();

ObjectInputStream oin = new ObjectInputStream(new FileInputStream(file));
Object newPerson = oin.readObject();
oin.close();
System.out.println(newPerson);

System.out.println(Person.getInstance() == newPerson); // 将获取的对象与Person类中的单例对象进行相等性比较
}
}执行上述应用程序后会得到如下结果:
arg constructor
[John, 31, MALE]
false值得注意的是,从文件person.out中获取的Person对象与Person类中的单例对象并不相等。为了能在序列化过程仍能保持单例的特性,可以在Person类中添加一个readResolve()方法,在该方法中直接返回Person的单例对象,如下所示:
public class Person implements Serializable {

private static class InstanceHolder {
private static final Person instatnce = new Person("John", 31, Gender.MALE)