弄明白Externalizable接口之前,需要先了解Java序列化和反序列化的原理,可参考这篇# Serializable序列化与反序列化原理。
1.Externalizable
1.序列化
其实了解过序列化原理后,会发现在writeOrdinaryObject()方法中,进行了逻辑判断,如果实现了Externalizable接口就进入了writeExternalData()方法。
private void writeOrdinaryObject(Object obj,
ObjectStreamClass desc,
boolean unshared)
throws IOException
{
if (extendedDebugInfo) {
debugInfoStack.push(
(depth == 1 ? "root " : "") + "object (class "" +
obj.getClass().getName() + "", " + obj.toString() + ")");
}
try {
desc.checkSerialize();
bout.writeByte(TC_OBJECT);
writeClassDesc(desc, false);
handles.assign(unshared ? null : obj);
if (desc.isExternalizable() && !desc.isProxy()) {//逻辑判断
writeExternalData((Externalizable) obj);//实现了Externalizable接口,进入此方法
} else {
writeSerialData(obj, desc);
}
} finally {
if (extendedDebugInfo) {
debugInfoStack.pop();
}
}
}
进入writeExternalData()方法。
private void writeExternalData(Externalizable obj) throws IOException {
PutFieldImpl oldPut = curPut;
curPut = null;
if (extendedDebugInfo) {
debugInfoStack.push("writeExternal data");
}
SerialCallbackContext oldContext = curContext;
try {
curContext = null;
if (protocol == PROTOCOL_VERSION_1) {
obj.writeExternal(this);
} else {
bout.setBlockDataMode(true);
obj.writeExternal(this);//调用了实现的writeExternal方法
bout.setBlockDataMode(false);
bout.writeByte(TC_ENDBLOCKDATA);
}
} finally {
curContext = oldContext;
if (extendedDebugInfo) {
debugInfoStack.pop();
}
}
curPut = oldPut;
}
会发现并没有做任何复杂的处理,就是直接调用实现了Externalizable接口的writeExternal()方法。
2.反序列化
了解过反序列化原理后,会发现在readOrdinaryObject()方法中,进行了逻辑判断,如果实现了Externalizable接口就进入了readExternalData()方法。
private Object readOrdinaryObject(boolean unshared)
throws IOException
{
if (bin.readByte() != TC_OBJECT) {
throw new InternalError();
}
ObjectStreamClass desc = readClassDesc(false);
desc.checkDeserialize();
Class<?> cl = desc.forClass();
if (cl == String.class || cl == Class.class
|| cl == ObjectStreamClass.class) {
throw new InvalidClassException("invalid class descriptor");
}
Object obj;
try {
obj = desc.isInstantiable() ? desc.newInstance() : null;
} catch (Exception ex) {
throw (IOException) new InvalidClassException(
desc.forClass().getName(),
"unable to create instance").initCause(ex);
}
passHandle = handles.assign(unshared ? unsharedMarker : obj);
ClassNotFoundException resolveEx = desc.getResolveException();
if (resolveEx != null) {
handles.markException(passHandle, resolveEx);
}
if (desc.isExternalizable()) {//逻辑判断
readExternalData((Externalizable) obj, desc);//实现了Externalizable接口,进入此方法
} else {
readSerialData(obj, desc);
}
handles.finish(passHandle);
if (obj != null &&
handles.lookupException(passHandle) == null &&
desc.hasReadResolveMethod())
{
Object rep = desc.invokeReadResolve(obj);
if (unshared && rep.getClass().isArray()) {
rep = cloneArray(rep);
}
if (rep != obj) {
// Android-removed: ObjectInputFilter logic, to be reconsidered. http://b/110252929
/*
// Filter the replacement object
if (rep != null) {
if (rep.getClass().isArray()) {
filterCheck(rep.getClass(), Array.getLength(rep));
} else {
filterCheck(rep.getClass(), -1);
}
}
*/
handles.setObject(passHandle, obj = rep);
}
}
return obj;
}
进入readExternalData()方法。
private void readExternalData(Externalizable obj, ObjectStreamClass desc)
throws IOException
{
SerialCallbackContext oldContext = curContext;
if (oldContext != null)
oldContext.check();
curContext = null;
try {
boolean blocked = desc.hasBlockExternalData();
if (blocked) {
bin.setBlockDataMode(true);
}
if (obj != null) {
try {
obj.readExternal(this);//调用了实现的readExternal方法
} catch (ClassNotFoundException ex) {
/*
* In most cases, the handle table has already propagated
* a CNFException to passHandle at this point; this mark
* call is included to address cases where the readExternal
* method has cons'ed and thrown a new CNFException of its
* own.
*/
handles.markException(passHandle, ex);
}
}
if (blocked) {
skipCustomData();
}
} finally {
if (oldContext != null)
oldContext.check();
curContext = oldContext;
}
}
会发现也并没有做任何复杂的处理,就是直接调用实现了Externalizable接口的readExternal()方法。
2.Externalizable VS Serializable
第一点
- Serializable 是标识接口
- Externalizable 接口继承于Serializable,实现该接口,需要重写readExternal和writeExternal方法
第二点
Serializable有两种方式进行对象的序列化
- 采用默认序列化方式,将非transatient和非static的属性进行序列化
- 编写readObject和writeObject完成部分属性的序列化
Externalizable接口只能通过实现writeExternal和readExternal方法,在方法中实现序列化和反序列化操作。
第三点
Externalizable接口的实现方式一定要有默认的无参构造函数
3.总结
我想Externalizable存在的意义,可能就是为了能完全自定义序列化的过程,来解决Serializable中序列化和反序列化时大量使用反射导致的性能问题吧!