Serialization and subclassing

Interfaces and classes designed for inheritance should rarely implement Serializable, since this would force a significant and (often unwanted) task on their implementors and subclasses.

However, even though most abstract classes don't implement Serializable, they may still need to allow their subclasses to do so, if desired.

There are two cases. If the abstract class has no state, then it can simply provide a no-argument constructor to its subclasses. If the abstract class has state, however, then there's more work to be done, as demonstrated in the following example.

Example


public abstract class Government {

  public Government(String aWinningParty) {
    init(aWinningParty);
    //never invoke an overridable method in a constructor
  }

  public final void raiseTaxes() {
    validateInit(); //always called by public methods
    //..elided
  }

  public final void lowerTaxes() {
    validateInit();
    //..elided
  }

  /**
  * A template method which calls a protected abstract method, to
  * be overridden by subclasses.
  */
  public boolean makeLaw(){
    validateInit();
    String bill = draftLegislation(); //protected, abstract method
    return vote(bill);
  }

  // PROTECTED

  /**
  * Each governament will draft legislation in a particular way.
  * A tyranny, for example, would not have wide debate between its
  * citizens.
  */
  protected abstract String draftLegislation();

  /**
  * This no-argument constructor is needed by subclass's Serialization
  * mechanism.
  */
  protected Government() {
    //empty
  }

  /**
  * Called by both this class's public constructor, and by a subclass's
  * readObject method. Note this method is final.
  */
  protected final void init(String aWinningParty){
    if (fIsInitialized) {
      throw new IllegalStateException("Cannot call init twice.");
    }
    fWinningParty = aWinningParty;
    fIsInitialized = true;
  }

  /**
  * Subclass will need access to the superclass's internal state,
  * either through public or protected gets. Note that the
  * get needs to be final.
  */
  protected final String getWinningParty() {
    return fWinningParty;
  }

  // PRIVATE
  private String fWinningParty;
  private boolean fIsInitialized = false;

  /**
  * Must be called by public methods.
  */
  private void validateInit() throws IllegalStateException {
    if (!fIsInitialized) {
      throw new IllegalStateException("Uninitialized object");
    }
  }

  private boolean vote(String aBill){
    return true; //toy implentation
  }
} 



import java.io.*;

/** A Serializable subclass. */
public final class Tyranny extends Government implements Serializable {

  public Tyranny(String aWinningParty) {
    super(aWinningParty);
  }

  // PROTECTED

  protected String draftLegislation() {
    return "Forbid all use of C++.";
  }

  // PRIVATE

  /**
  * Custom deserialization is needed.
  */
  private void readObject(
    ObjectInputStream aStream
  ) throws IOException, ClassNotFoundException {
    aStream.defaultReadObject();
    //manually deserialize and init superclass
    String winningParty = (String)aStream.readObject();
    init(winningParty);
  }

  /**
  * Custom serialization is needed.
  */
  private void writeObject(ObjectOutputStream aStream) throws IOException {
    aStream.defaultWriteObject();
    //manually serialize superclass
    aStream.writeObject(getWinningParty());
  }
} 



See Also :
Implementing Serializable
Designing for subclassing
Would you use this technique?
Yes   No   Undecided   
© 2014 Hirondelle Systems | Source Code | Contact | License | RSS
Individual code snippets can be used under this BSD license - Last updated on September 21, 2013.
Over 2,000,000 unique IPs last year - Built with WEB4J.
- In Memoriam : Bill Dirani -