前面寫了一個(gè)序列化的文章,這次重新整理一下。

1.Serialize概念
Java的對(duì)象序列化就是將那些實(shí)現(xiàn)了Serializable接口的對(duì)象轉(zhuǎn)換成一個(gè)字節(jié)序列。并能夠
在以后將這個(gè)字節(jié)完全恢復(fù)為原來(lái)的對(duì)象。
對(duì)象序列化的概念加入到語(yǔ)言當(dāng)中就是為了支持兩種主要特性

一是Java的遠(yuǎn)程方法調(diào)用(Remote Method Invocation, RMI)。當(dāng)向遠(yuǎn)程對(duì)象發(fā)送消息時(shí),
需要通過(guò)序列化來(lái)傳輸參數(shù)和返回值。

二是Javabean對(duì)象序列化。有些服務(wù)器通過(guò)將所有的SESSION 數(shù)據(jù)(包括BEAN)寫入磁盤來(lái)支持任意長(zhǎng)的SESSION生命期,即使服務(wù)器停機(jī)也不會(huì)丟失。當(dāng)服務(wù)器重新啟動(dòng)后,串行化的數(shù)據(jù)被恢復(fù)。同樣的理由,在重負(fù)載的站點(diǎn)上支持服務(wù)器分簇的環(huán)境中,許多服務(wù)器通過(guò)串行化來(lái)復(fù)制SESSION。如果你的BEAN不支持串行化,服務(wù)器就不能正確地保存和傳輸類。

只要對(duì)象實(shí)現(xiàn)了Serializable接口,對(duì)象的序列化處理就會(huì)非常簡(jiǎn)單。
2.Serialize方法
要序列化一個(gè)對(duì)象,首先要?jiǎng)?chuàng)建某些OutputStream對(duì)象,然后將其封裝在一個(gè)ObjectOutputStream對(duì)象內(nèi)。
這時(shí),只需要調(diào)用writeObject()即可將對(duì)象序列化,并將其發(fā)送給OutputStream。反之,將一個(gè)序列化對(duì)象還原為一個(gè)對(duì)象,需要將一個(gè)InputStream封裝在ObjectInputStream內(nèi),然后調(diào)用readObject()。
OutputStream和InputStream常用的是ByteArrayOutputStream/FileOutputStream和ByteArrayInputStream/FileInputStream。

下面兩個(gè)類以ByteArray方式實(shí)現(xiàn)序列化:

public final class Serialization
{

    /**
     * Serialize the object into a byte array.
     */
    public static byte[] serialize( Object obj )
        throws IOException
    {
        ByteArrayOutputStream  baos;
        ObjectOutputStream     oos;

        baos = new ByteArrayOutputStream();
        oos = new ObjectOutputStream( baos );
        oos.writeObject( obj );
        oos.close();

        return baos.toByteArray();
    }


    /**
     * Deserialize an object from a byte array
     */
    public static Object deserialize( byte[] buf )
        throws ClassNotFoundException, IOException
    {
        ByteArrayInputStream  bais;
        ObjectInputStream     ois;

        bais = new ByteArrayInputStream( buf );
        ois = new ObjectInputStream( bais );
        return ois.readObject();
    }

}

public class DefaultSerializer
    implements Serializer
{

   
    public static final DefaultSerializer INSTANCE = new DefaultSerializer();
   
   
    /**
     * Construct a DefaultSerializer.
     */
    public DefaultSerializer()
    {
        // no op
    }

   
    /**
     * Serialize the content of an object into a byte array.
     *
     * @param obj Object to serialize
     * @return a byte array representing the object's state
     */
     public byte[] serialize( Object obj )
        throws IOException
     {
         return Serialization.serialize( obj );
     }
       
       
    /**
     * Deserialize the content of an object from a byte array.
     *
     * @param serialized Byte array representation of the object
     * @return deserialized object
     */
     public Object deserialize( byte[] serialized )
        throws IOException
     {
         try {
            return Serialization.deserialize( serialized );
         } catch ( ClassNotFoundException except ) {
            throw new WrappedRuntimeException( except );
         }
     }

}

File方式的序列化大致如下:

ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(out.txt));
out.writeObject(obj);
out.close();

ObjectInputStream in = new ObjectInputStream(new FileInputStream(out.txt));
Object obj = (Object)in.readObject();
in.close();

3.Serialize定制

缺省的序列化機(jī)制并不難操縱,如果有特殊的需求那又該怎么辦?例如,也許要考慮特殊的安全問(wèn)題,而且
你不希望對(duì)象的某一部分被序列化;或者一個(gè)對(duì)象被還原后,某子對(duì)象需要重新創(chuàng)建,從而不需要將該子對(duì)象
序列化。在這樣的特殊情況下,可通過(guò)實(shí)現(xiàn)Externalizable接口來(lái)對(duì)序列化過(guò)程進(jìn)行控制。這個(gè)Externalizable
接口繼承了Serializable接口,同時(shí)增加了兩個(gè)方法:writeExternal(ObjectOutput out)和readExternal(ObjectInput in)

Serializable對(duì)象完全以它存儲(chǔ)的二進(jìn)制位為基礎(chǔ)來(lái)構(gòu)造,而不用調(diào)用構(gòu)造器。而對(duì)于一個(gè)Externalizable對(duì)象
缺省構(gòu)造器都會(huì)被調(diào)用,然后調(diào)用readExternal()。下面列子中,如果Blip3()構(gòu)造器注釋掉,程序會(huì)報(bào)錯(cuò):no valid constructor


// Reconstructing an externalizable object.
// From 'Thinking in Java, 3rd ed.' (c) Bruce Eckel 2002
// www.BruceEckel.com. See copyright notice in CopyRight.txt.
import com.bruceeckel.simpletest.*;
import java.io.*;
import java.util.*;

public class Blip3 implements Externalizable {
  private static Test monitor = new Test();
  private int i;
  private String s; // No initialization
  public Blip3() {
    System.out.println("Blip3 Constructor");
    // s, i not initialized
  }
  public Blip3(String x, int a) {
    System.out.println("Blip3(String x, int a)");
    s = x;
    i = a;
    // s & i initialized only in nondefault constructor.
  }
  public String toString() { return s + i; }
  public void writeExternal(ObjectOutput out)
  throws IOException {
    System.out.println("Blip3.writeExternal");
    // You must do this:
    out.writeObject(s);
    out.writeInt(i);
  }
  public void readExternal(ObjectInput in)
  throws IOException, ClassNotFoundException {
    System.out.println("Blip3.readExternal");
    // You must do this:
    s = (String)in.readObject();
    i = in.readInt();
  }
  public static void main(String[] args)
  throws IOException, ClassNotFoundException {
    System.out.println("Constructing objects:");
    Blip3 b3 = new Blip3("A String ", 47);
    System.out.println(b3);
    ObjectOutputStream o = new ObjectOutputStream(
      new FileOutputStream("Blip3.out"));
    System.out.println("Saving object:");
    o.writeObject(b3);
    o.close();
    // Now get it back:
    ObjectInputStream in = new ObjectInputStream(
      new FileInputStream("Blip3.out"));
    System.out.println("Recovering b3:");
    b3 = (Blip3)in.readObject();
    System.out.println(b3);
    monitor.expect(new String[] {
      "Constructing objects:",
      "Blip3(String x, int a)",
      "A String 47",
      "Saving object:",
      "Blip3.writeExternal",
      "Recovering b3:",
      "Blip3 Constructor",
      "Blip3.readExternal",
      "A String 47"
    });
  }
}