10.3 Externalizable Classes
The Externalizable interface extends
Serializable and defines the
writeExternal( ) and readExternal(
) methods. An Externalizable object may
be serialized as other Serializable objects are,
but the serialization mechanism calls writeExternal(
) and readExternal( ) to perform the
serialization and deserialization. Unlike the readObject(
) and writeObject( ) methods in Example 10-2, the readExternal( ) and
writeExternal( ) methods can't
call the defaultReadObject( ) and
defaultWriteObject( ) methods: they must read and
write the complete state of the object by themselves.
It is useful to
declare an object Externalizable when the object
already has an existing file format or when you want to accomplish
something that is simply not possible with the standard serialization
methods. Example 10-3 defines the
CompactIntList class, an
Externalizable subclass of the
IntList class of Example 2-7.
CompactIntList makes the assumption that it is
typically used to store small integers that fit in two bytes instead
of four; it implements Externalizable so it can
define a serialized form that is more compact than the format used by
ObjectOutputStream and
ObjectInputStream.
Example 10-3. CompactIntList.java
package je3.serialization;
import je3.classes.IntList;
import java.io.*;
/**
* This subclass of IntList assumes that most of the integers it contains are
* less than 32,000. It implements Externalizable so that it can define a
* compact serialization format that takes advantage of this fact.
**/
public class CompactIntList extends IntList implements Externalizable {
/**
* This version number is here in case a later revision of this class wants
* to modify the externalization format, but still retain compatibility
* with externalized objects written by this version
**/
static final byte version = 1;
/**
* This method from the Externalizable interface is responsible for saving
* the complete state of the object to the specified stream. It can write
* anything it wants as long as readExternal( ) can read it.
**/
public void writeExternal(ObjectOutput out) throws IOException {
trim( ); // Compact the list to its current size
out.writeByte(version); // Start with our version number.
out.writeInt(size); // Output the number of array elements
for(int i = 0; i < size; i++) { // Now loop through the array
int n = data[i]; // The array element to write
if ((n <= Short.MAX_VALUE) && (n > Short.MIN_VALUE)) {
// If n fits in a short and is not Short.MIN_VALUE, then write
// it out as a short, saving ourselves two bytes
out.writeShort(n);
}
else {
// Otherwise write out the special value Short.MIN_VALUE to
// signal that the number does not fit in a short, and then
// output the number using a full 4 bytes, for 6 bytes total
out.writeShort(Short.MIN_VALUE);
out.writeInt(n);
}
}
}
/**
* This Externalizable method is responsible for completely restoring the
* state of the object. A no-arg constructor will be called to recreate
* the object, and this method must read the state written by
* writeExternal( ) to restore the object's state.
**/
public void readExternal(ObjectInput in)
throws IOException, ClassNotFoundException
{
// Start by reading and verifying the version number.
byte v = in.readByte( );
if (v != version)
throw new IOException("CompactIntList: unknown version number");
// Read the number of array elements, and make array that big
int newsize = in.readInt( );
setCapacity(newsize); // A protected method inherited from IntList
this.size = newsize; // Save this size.
// Now read that many values from the stream
for(int i = 0; i < newsize; i++) {
short n = in.readShort( );
if (n != Short.MIN_VALUE) data[i] = n;
else data[i] = in.readInt( );
}
}
/** A main( ) method to prove that it works */
public static void main(String[ ] args) throws Exception {
CompactIntList list = new CompactIntList( );
for(int i = 0; i < 100; i++) list.add((int)(Math.random( )*40000));
CompactIntList copy = (CompactIntList)Serializer.deepclone(list);
if (list.equals(copy)) System.out.println("equal copies");
Serializer.store(list, new File("compactintlist.ser"));
}
}
|