调用ObjectInputSream类的readObject方法对实现了Serializable的对象进行反序列化。
public SerialObject inputObj(String path) throws Exception {
ObjectInputStream inputStream = new ObjectInputStream(new FileInputStream(path));
SerialObject obj = (SerialObject) inputStream.readObject();
inputStream.close();
return obj;
}
ObjectInputSream的readObject方法,实际调用了readObject0(false)方法:
public final Object readObject()
throws IOException, ClassNotFoundException {
...
Object obj = readObject0(false);
handles.markDependency(outerHandle, passHandle);
ClassNotFoundException ex = handles.lookupException(passHandle);
if (ex != null) {
throw ex;
}
if (depth == 0) {
vlist.doCallbacks();
}
return obj;
...
}
可以看到readObject0中会根据不同的对象类型,执行不同反序列化过程。这里只看对象类型的反序列化过程,即TC_OBJECT的情形。此时调用readOrdinaryObject方法进行反序列化。
private Object readObject0(boolean unshared) throws IOException {
...
byte tc;
while ((tc = bin.peekByte()) == TC_RESET) {
bin.readByte();
handleReset();
}
depth++;
try {
switch (tc) {
case TC_NULL:
return readNull();
case TC_REFERENCE:
return readHandle(unshared);
case TC_CLASS:
return readClass(unshared);
case TC_CLASSDESC:
case TC_PROXYCLASSDESC:
return readClassDesc(unshared);
case TC_STRING:
case TC_LONGSTRING:
return checkResolve(readString(unshared));
case TC_ARRAY:
return checkResolve(readArray(unshared));
case TC_ENUM:
return checkResolve(readEnum(unshared));
case TC_OBJECT:
return checkResolve(readOrdinaryObject(unshared));
case TC_EXCEPTION:
IOException ex = readFatalException();
throw new WriteAbortedException("writing aborted", ex);
case TC_BLOCKDATA:
case TC_BLOCKDATALONG:
if (oldMode) {
bin.setBlockDataMode(true);
bin.peek(); // force header read
throw new OptionalDataException(
bin.currentBlockRemaining());
} else {
throw new StreamCorruptedException(
"unexpected block data");
}
case TC_ENDBLOCKDATA:
if (oldMode) {
throw new OptionalDataException(true);
} else {
throw new StreamCorruptedException(
"unexpected end of block data");
}
default:
throw new StreamCorruptedException(
String.format("invalid type code: %02X", tc));
}
} finally {
depth--;
bin.setBlockDataMode(oldMode);
}
...
}
readOrdinaryObject方法,会通过反射调用对象的无参构造函数创建对象。这就是为什么说,“序列化的类需要提供能够被访问的无参构造函数,否则会报错”的原因。
根据序列化类实现了Externalizable或Serializable的接口,分别调用不同的方法。这里先讨论实现Serializable接口的情形。此时调用readSerialData方法。
private Object readOrdinaryObject(boolean unshared)
throws IOException {
...
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);
}
...
if (desc.isExternalizable()) {
readExternalData((Externalizable) obj, desc);
} else {
readSerialData(obj, desc);
}
...
return obj;
}
readSerialData方法,判断是否有自定义的反序列化函数,有的话,执行自定义的反序列化方法;否则执行defaultReadFields。
private void readSerialData(Object obj, ObjectStreamClass desc)
throws IOException {
...
if (obj == null || handles.lookupException(passHandle) != null) {
defaultReadFields(null, slotDesc); // skip field values
} else if (slotDesc.hasReadObjectMethod()) {
...
slotDesc.invokeReadObject(obj, this);
...
} else {
defaultReadFields(obj, slotDesc);
}
...
}
自定义的反序列方法有readObject和readResolve方法。在初始化ObjectStreamClass的时候,通过反射查找是否存在这两个方法。
可以看到只有实现Serializable接口,并提供readObject / readResolve方法才起作用。实现Externalizable接口是无效的。并且若同时提供readResolve和readObject方法,前者会覆盖后者。
private ObjectStreamClass(final Class> cl) {
// 是否实现Externalizable接口的方式
if (externalizable) {
cons = getExternalizableConstructor(cl);
} else {
cons = getSerializableConstructor(cl);
writeObjectMethod = getPrivateMethod(cl, "writeObject",
new Class>[] { ObjectOutputStream.class },
Void.TYPE);
readObjectMethod = getPrivateMethod(cl, "readObject",
new Class>[] { ObjectInputStream.class },
Void.TYPE);
readObjectNoDataMethod = getPrivateMethod(
cl, "readObjectNoData", null, Void.TYPE);
hasWriteObjectData = (writeObjectMethod != null);
}
writeReplaceMethod = getInheritableMethod(
cl, "writeReplace", null, Object.class);
readResolveMethod = getInheritableMethod(
cl, "readResolve", null, Object.class);
...
}
若是实现了自定义序列化的方法(readObject / readResolve),则直接反射调用对象的方法完成反序列化。
void invokeReadObject(Object obj, ObjectInputStream in)
throws ClassNotFoundException, IOException,
UnsupportedOperationException {
requireInitialized();
if (readObjectMethod != null) {
try {
readObjectMethod.invoke(obj, new Object[]{ in });
...
}
...
}
系统默认反序列化过程,调用defaultReadFields完成,首先反序列化基本数据类型,填充到obj。然后针对对象类型,遍历循环调用readObject0进行反序列化。
private void defaultReadFields(Object obj, ObjectStreamClass desc)
throws IOException {
...
int primDataSize = desc.getPrimDataSize();
if (primVals == null || primVals.length < primDataSize) {
primVals = new byte[primDataSize];
}
bin.readFully(primVals, 0, primDataSize, false);
if (obj != null) {
desc.setPrimFieldValues(obj, primVals);
}
...
for (int i = 0; i < objVals.length; i++) {
ObjectStreamField f = fields[numPrimFields + i];
objVals[i] = readObject0(f.isUnshared());
}
...
}
实现Externalizable接口的反序列化
在readOrdinaryObject方法,若序列化类实现了Externalizable接口,则调用readExternalData完成反序列化过程。
这里既是调用序列化类实现的readExternal方法完成反序列化。
private void readExternalData(Externalizable obj, ObjectStreamClass desc)
throws IOException {
...
if (obj != null) {
try {
obj.readExternal(this);
} catch (ClassNotFoundException ex) {
...
}



