序列化和持久化
序列化和持久化都是将对象转换成二进制数据,序列化的目的是便于传输,而持久化的目的是进行存储。持久化必须要进行序列化,而序列化不一定要进行持久化。反序列化,既是将二进制数据还原成为对象的过程。
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);
}
...
}