What are the writeReplace() and readResolve() methods used for?

Chuck McCorvey

These methods are used to allow an object to provide an alternative representation for itself within an ObjectStream. Consider for instance the common means of implementing an enumerated type:

public class Gender implements Serializable {
  public final static Gender MALE   = new Gender("Male");
  public final static Gender FEMALE = new Gender("Female");

  private String name;

  private Gender(String name) {
    this.name = name;
  }
}
This works fine within one JVM; there will be at most two Gender objects created, no matter how often you use Gender.MALE and Gender.FEMALE in your code. However, consider what happens when an instance of this class is serialized across JVMs. The ObjectInputStream will create a new instance of Gender that has the same value as the original instance. So, if you have many thousands objects that have been de-serialized via RMI you might end up with many thousands of extra instances of Gender. The writeReplace() and readResolve() methods are the hook to solve this problem.

One way of eliminating the extra instances and some of the unnecessary heap allocation would be to do something like this:

public class Gender implements Serializable {
  public final static Gender MALE   = new Gender("Male");
  public final static Gender FEMALE = new Gender("Female");

  private String name;

  private Gender(String name) {
    this.name = name;
  }

  Object writeReplace() throws ObjectStreamException {
    if (this.equals(MALE)) {
      return SerializedForm.MALE_FORM;
    } else {
      return SerializedForm.FEMALE_FORM;
    }
  }

  private static class SerializedForm implements Serializable {

    final static SerializedForm MALE_FORM   = new SerializedForm(0);
    final static SerializedForm FEMALE_FORM = new SerializedForm(1);

    private int value;

    SerializedForm(int value) {
      this.value = value;
    }

    Object readResolve() throws ObjectStreamException {
      if (value == MALE_FORM.value) {
        return Gender.MALE;
      } else {
        return Gender.FEMALE;
      }
    }
  }
}
This also guarantees that in all cases where genderInstance.equals(MALE) is true, genderInstance == Gender.MALE is also true.

This was a trivial example. I've used this mechanism in other instances where a great deal of storage or time could be saved by serializing only a shorthand or mnemonic form of the object - consider the definition of a currency which could be serialized as only its mnemonic symbol.

0 Comments  (click to add your comment)
Comment and Contribute

 

 

 

 

 


(Maximum characters: 1200). You have 1200 characters left.

 

 

About | Sitemap | Contact