序列化和持久化

        序列化和持久化都是将对象转换成二进制数据,序列化的目的是便于传输,而持久化的目的是进行存储。持久化必须要进行序列化,而序列化不一定要进行持久化。反序列化,既是将二进制数据还原成为对象的过程。

 Serializable接口

        Java的序列化和反序列化,需要通过ObjectOutputStream和ObjectInputStream这两个类实现。继承自Serialable接口,表示当前类可以被ObjectOutputStream序列化,以及可以被ObjectInputStream反序列化。

public interface Serializable {
}
public class SerialObject implements Serializable {
    private String filed1;
}

序列化过程

        调用ObjectOutputSream类的writeObject方法对实现了Serializable的对象进行序列化。 

public void serialObj(SerialObject obj, String path) {
    ObjectOutputStream outputStream = null;
    try {
        outputStream = new ObjectOutputStream(new FileOutputStream(path));
        outputStream.writeObject(obj);
        outputStream.close();
    } catch (IOException e) { 
        e.printStackTrace();
    } finally {
        if (outputStream != null) {
            try {
                outputStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

         ObjectOutputSream的writeObject继续调用writeObject0方法:

public final void writeObject(Object obj) throws IOException {
    if (enableOverride) {
        writeObjectOverride(obj);
        return;
    }
    try {
        writeObject0(obj, false);
    } catch (IOException ex) {
    ...
}

        writeObject0方法中,针对不同类型对象,执行不同序列化过程。我们自定义的对象在最后,判断是否实现了Serializable,若没有实现则会抛出NotSerializableException的异常。

private void writeObject0(Object obj, boolean unshared)
        throws IOException{
    ...
    // remaining cases
    // BEGIN Android-changed: Make Class and ObjectStreamClass replaceable.
    if (obj instanceof Class) {
        writeClass((Class) obj, unshared);
    } else if (obj instanceof ObjectStreamClass) {
        writeClassDesc((ObjectStreamClass) obj, unshared);
        // END Android-changed: Make Class and ObjectStreamClass replaceable.
    } else if (obj instanceof String) {
        writeString((String) obj, unshared);} else if (cl.isArray()) {
        writeArray(obj, desc, unshared);
    } else if (obj instanceof Enum) {
        writeEnum((Enum<?>) obj, desc, unshared);
    } else if (obj instanceof Serializable) {
        writeOrdinaryObject(obj, desc, unshared);
    } else { 
        if (extendedDebugInfo) {
            throw new NotSerializableException(
                cl.getName() + "\n" + debugInfoStack.toString());
        } else {
            throw new NotSerializableException(cl.getName());
        }
    }
    ...
}

* 枚举 @{ 

          对枚举的情形进行序列化,只是简单的记录枚举类型和枚举对象的名称。

private void writeEnum(Enum<?> en, ObjectStreamClass desc, boolean unshared)
        throws IOException {
    bout.writeByte(TC_ENUM);
    ObjectStreamClass sdesc = desc.getSuperDesc();
    writeClassDesc((sdesc.forClass() == Enum.class) ? desc : sdesc, false);
    handles.assign(unshared ? null : en);
    writeString(en.name(), false);
}

        反序列化枚举时,根据记录的枚举名称,通过valueOf从枚举类中直接获取对象。经过序列化、反序列化枚举对象依然是单例。因此说枚举是“天然的单例”。

private Enum<?> readEnum(boolean unshared) throws IOException {
    ...
    try {
        @SuppressWarnings("unchecked")
        Enum<?> en = Enum.valueOf((Class)cl, name);
        result = en;
    } catch (IllegalArgumentException ex) {
    
    ...    
}

@ } 枚举  

         继续调用writeOrdinaryObject方法进行序列化。判断是实现Externalizable接口,则调用writeExternalData方法;如果实现Serializable,则执行writeSerialData方法进行序列化。实现Externalizable接口是Java另一种序列化的方式,这里我们看实现Serializable的方式。

private void writeOrdinaryObject(Object obj,
                                 ObjectStreamClass desc,
                                 boolean unshared) 
        throws IOException {
    ...
    if (desc.isExternalizable() && !desc.isProxy()) {
        writeExternalData((Externalizable) obj);
    } else {
        writeSerialData(obj, desc);
    }
    ...
}

         writeSerialData方法中判断是否重写了writeObject方法,若有,则通过反射调用用户自定义的wiriteObjet方法(这里相当于用户自定义序列化);否则,执行defaultWriteFields方法:

private void writeSerialData(Object obj, ObjectStreamClass desc)
        throws IOException{
    ...
    if (slotDesc.hasWriteObjectMethod()) {
        ...
        slotDesc.invokeWriteObject(obj, this);
        ...
    } else {
        defaultWriteFields(obj, slotDesc);
    }
    ...
}

        defaultWriteFields将基本数据类型写入按照一定格式以字节流写入文件,递归调用writeObject0序列化其他对象类型成员。

private void defaultWriteFields(Object obj, ObjectStreamClass desc)
        throws IOException
{    
    ...
    desc.getPrimFieldValues(obj, primVals);
    bout.write(primVals, 0, primDataSize, false);
    ...
    for (int i = 0; i < objVals.length; i++) {
        ...
        try {
            writeObject0(objVals[i],fields[numPrimFields + i].isUnshared());
        }
        ...
    }
    ...
}

Externalizable序列化分析

        在writeOrdinaryObject方法中,如果类实现的事Externalizable接口,则会调用writeExternalData((Externalizable) obj)方法进行序列化。在这个方法中,主要调用writeExternal进行序列化。这也是为什么实现该接口进行序列化,需要重写writeExternal/readExternal方法。

private void writeExternalData(Externalizable obj) throws IOException {
    ... 
    if (protocol == PROTOCOL_VERSION_1) {
        obj.writeExternal(this);
    } else {
        bout.setBlockDataMode(true);
        obj.writeExternal(this);
        bout.setBlockDataMode(false);
        bout.writeByte(TC_ENDBLOCKDATA);
    }
    ...
}