Do not implement Serializable lightly, since it restricts future flexibility, and publicly exposes class implementation details which are usually private. As well, implementing Serializable correctly is not trivial.
The serialVersionUID is a universal version identifier for a Serializable class. Deserialization uses this number to ensure that a loaded class corresponds exactly to a serialized object. If no match is found, then an InvalidClassException is thrown.
Guidelines for serialVersionUID :
always include it as a field, for example: "private static final long serialVersionUID=7526472295622776147L; " include this field even in the first version of the class, as a reminder of its importance do not change the value of this field in future versions, unless you are knowingly making changes to the class which will render it incompatible with old serialized objects new versions of Serializable classes may or may not be able to read old serialized objects; it depends upon the nature of the change; provide a pointer to Sun's guidelines for what constitutes a compatible change, as a convenience to future maintainersIn Windows, generate serialVersionUID using the JDK's graphical tool like so : use Control Panel | System | Environment to set the classpath to the correct directory run serialver -show from the command line point the tool to the class file including the package, for example, finance.stock.Account - without the .class (here are the serialver docs for both Win and Unix)readObject and writeObject : readObject implementations always start by calling default methods deserialization must be treated as any constructor : validate the object state at the end of deserializing - this implies thatreadObject should almost always be implemented in Serializable classes, such that this validation is performed. deserialization must be treated as any constructor : if constructors make defensive copies for mutable object fields, so mustreadObject when serializing a Collection, store the number of objects in the Collection as well, and use this number to read them back in upon deserialization; avoid tricks using nullOther points : use javadoc's @serial tag to denote Serializable fields the .ser extension is conventionally used for files representing serialized objects no static or transient fields undergo default serialization extendable classes should not be Serializable, unless necessary inner classes should rarely, if ever, implement Serializable container classes should usually follow the style of Hashtable, which implements Serializable by storing keys and values, as opposed to a large hash table data structure
Exampleimport java.io.Serializable;import java.text.StringCharacterIterator;import java.util.*;import java.io.*;public final class SavingsAccount implements Serializable {public SavingsAccount (String aFirstName, String aLastName, int aAccountNumber, Date aDateOpened){super();setFirstName(aFirstName);setLastName(aLastName);setAccountNumber(aAccountNumber);//make a defensive copy of the mutable Date passed to the constructor setDateOpened( new Date(aDateOpened.getTime()) );//there is no need here to call validateState. }public SavingsAccount () {this ("FirstName", "LastName", 0, new Date(System.currentTimeMillis()));}public final String getFirstName() {return fFirstName;}public final String getLastName(){return fLastName;}public final int getAccountNumber() {return fAccountNumber;}public final Date getDateOpened() {return new Date(fDateOpened.getTime());}public final void setFirstName( String aNewFirstName ) {validateName(aNewFirstName);fFirstName=aNewFirstName;}public final void setLastName ( String aNewLastName ) {validateName(aNewLastName);fLastName=aNewLastName;}public final void setAccountNumber( int aNewAccountNumber ) {validateAccountNumber(aNewAccountNumber);fAccountNumber=aNewAccountNumber;}public final void setDateOpened( Date aNewDate ){//make a defensive copy of the mutable date object Date newDate=new Date( aNewDate.getTime());validateDateOpened( newDate );fDateOpened=newDate;}// PRIVATE //private String fFirstName;private String fLastName;private int fAccountNumber;private Date fDateOpened;private static final long serialVersionUID=7526471155622776147L;private void validateState() {validateAccountNumber(fAccountNumber);validateName(fFirstName);validateName(fLastName);validateDateOpened(fDateOpened);}private void validateName(String aName){boolean nameHasContent=(aName !=null) && (!aName.equals(""));if (!nameHasContent){throw new IllegalArgumentException("Names must be non-null and non-empty.");}StringCharacterIterator iterator=new StringCharacterIterator(aName);char character=iterator.current();while (character !=StringCharacterIterator.DONE ){boolean isValidChar=(Character.isLetter(character) ||Character.isSpaceChar(character) ||character=="\'');if ( isValidChar ) {//do nothing }else {String message="Names can contain only letters, spaces, and apostrophes.";throw new IllegalArgumentException(message);}character=iterator.next();}}private void validateAccountNumber(int aAccountNumber){if (aAccountNumber< 0) {String message="Account Number must be greater than or equal to 0.";throw new IllegalArgumentException(message);}}private void validateDateOpened( Date aDateOpened ) {if( aDateOpened.getTime()<0 ) {throw new IllegalArgumentException("Date Opened must be after 1970.");}}private void readObject(ObjectInputStream aInputStream) throws ClassNotFoundException, IOException {//always perform the default de-serialization first aInputStream.defaultReadObject();//make defensive copy of the mutable Date field fDateOpened=new Date( fDateOpened.getTime() );//ensure that object state has not been corrupted or tampered with maliciously validateState();}private void writeObject(ObjectOutputStream aOutputStream) throws IOException {//perform the default serialization for all non-transient, non-static fields aOutputStream.defaultWriteObject();}}