1.为什么要序列化?
- 把数据进行本地存储
- 我们知道数据只能以二进制的形式在网络中传输,JavaBean对象在网络中传输时所以也需要用到序列化技术
- IPC通信(因为进程内存的隔离,所以需要通过序列化传输数据)
2.什么是序列化和反序列化
- 序列化:把Java对象转换为字节序列的过程。
- 反序列化:把字节序列恢复为Java对象的过程。
3.序列化和反序列化底层原理
在分析之前,我们需要思考Java序列化的几个问题:
- 序列化为什么要实现Serializable?
- 序列化为什么要重写serialVersionUID和它的作用是什么?
- 序列化的过程中transient和static修饰的字段为什么会被过滤?
1.序列化过程
序列化API调用
Person p = new Person();
ObjectOutputStream outputStream = new ObjectOutputStream(new FileOutputStream(new File(localFile)));
outputStream.writeObject(p);//写入文件
初始化构造函数
public ObjectOutputStream(OutputStream out) throws IOException {
verifySubclass();
bout = new BlockDataOutputStream(out);
handles = new HandleTable(10, (float) 3.00);
subs = new ReplaceTable(10, (float) 3.00);
enableOverride = false;//关闭了覆盖能力
writeStreamHeader();//写入序列化文件头
bout.setBlockDataMode(true);
if (extendedDebugInfo) {
debugInfoStack = new DebugTraceInfoStack();
} else {
debugInfoStack = null;
}
}
我们看一下writeStreamHeader()方法,就是一些基本头标识的写入。
protected void writeStreamHeader() throws IOException {
bout.writeShort(STREAM_MAGIC);
bout.writeShort(STREAM_VERSION);
}
进入writeObject()方法。
public final void writeObject(Object obj) throws IOException {
if (enableOverride) {//初始化时设置了false,不会走这里
writeObjectOverride(obj);
return;
}
try {
writeObject0(obj, false);//直接调用了这个方法
} catch (IOException ex) {
if (depth == 0) {
// BEGIN Android-changed: Ignore secondary exceptions during writeObject().
// writeFatalException(ex);
try {
writeFatalException(ex);
} catch (IOException ex2) {
// If writing the exception to the output stream causes another exception there
// is no need to propagate the second exception or generate a third exception,
// both of which might obscure details of the root cause.
}
// END Android-changed: Ignore secondary exceptions during writeObject().
}
throw ex;
}
}
进入writeObject0()方法。
/**
* Underlying writeObject/writeUnshared implementation.
*/
private void writeObject0(Object obj, boolean unshared)
throws IOException
{
boolean oldMode = bout.setBlockDataMode(false);
depth++;
try {
... 代码省略
// check for replacement object
Object orig = obj;
Class<?> cl = obj.getClass();
ObjectStreamClass desc;//重点关注这个类
...代码省略
Class repCl;
desc = ObjectStreamClass.lookup(cl, true);//对desc对象进行了初始化
if (desc.hasWriteReplaceMethod() &&
(obj = desc.invokeWriteReplace(obj)) != null &&
(repCl = obj.getClass()) != cl)
{
cl = repCl;
desc = ObjectStreamClass.lookup(cl, true);
}
// END Android-changed: Make only one call to writeReplace.
if (enableReplace) {
Object rep = replaceObject(obj);
if (rep != obj && rep != null) {
cl = rep.getClass();
desc = ObjectStreamClass.lookup(cl, true);
}
obj = rep;
}
...代码省略
//可以看出下面这些类型都是可以进行写入操作的
if (obj instanceof Class) {
writeClass((Class) obj, unshared);
} else if (obj instanceof ObjectStreamClass) {
writeClassDesc((ObjectStreamClass) obj, unshared);
} 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) {
//实现Serializable会执行下面这个方法
//第一个问题序列化为什么要实现Serializable?这就有了答案,Serializable只是一个标记接口,本身没有任何意义。
writeOrdinaryObject(obj, desc, unshared);
} else {
if (extendedDebugInfo) {
throw new NotSerializableException(
cl.getName() + "\n" + debugInfoStack.toString());
} else { //所以没有实现Serializable接口是会报错的
throw new NotSerializableException(cl.getName());
}
}
} finally {
depth--;
bout.setBlockDataMode(oldMode);
}
}
在writeObject0()方法中做了两件重要的事
- 通过ObjectStreamClass.lookup(cl, true)方法,初始化了ObjectStreamClass对象
- 根据不同写入类型,进行不同的操作
首先,我们先进入ObjectStreamClass.lookup(cl, true)方法。
static ObjectStreamClass lookup(Class<?> cl, boolean all) {
if (!(all || Serializable.class.isAssignableFrom(cl))) {
return null;
}
processQueue(Caches.localDescsQueue, Caches.localDescs);
WeakClassKey key = new WeakClassKey(cl, Caches.localDescsQueue);
//下面先是从缓存中获取对象,首次进入都是没有
Reference<?> ref = Caches.localDescs.get(key);
Object entry = null;
if (ref != null) {
entry = ref.get();
}
EntryFuture future = null;
if (entry == null) {
EntryFuture newEntry = new EntryFuture();
Reference<?> newRef = new SoftReference<>(newEntry);
do {
if (ref != null) {
Caches.localDescs.remove(key, ref);
}
ref = Caches.localDescs.putIfAbsent(key, newRef);
if (ref != null) {
entry = ref.get();
}
} while (ref != null && entry == null);
if (entry == null) {
future = newEntry;
}
}
//如果缓存中存在,就直接返回
if (entry instanceof ObjectStreamClass) { // check common case first
return (ObjectStreamClass) entry;
}
if (entry instanceof EntryFuture) {
future = (EntryFuture) entry;
if (future.getOwner() == Thread.currentThread()) {
/*
* Handle nested call situation described by 4803747: waiting
* for future value to be set by a lookup() call further up the
* stack will result in deadlock, so calculate and set the
* future value here instead.
*/
entry = null;
} else {
entry = future.get();
}
}
if (entry == null) {
try {
//缓存获取失败,直接创建对象
entry = new ObjectStreamClass(cl);
} catch (Throwable th) {
entry = th;
}
if (future.set(entry)) {
Caches.localDescs.put(key, new SoftReference<Object>(entry));//存入缓存
} else {
// nested lookup call already set future
entry = future.get();
}
}
if (entry instanceof ObjectStreamClass) {
return (ObjectStreamClass) entry;
} else if (entry instanceof RuntimeException) {
throw (RuntimeException) entry;
} else if (entry instanceof Error) {
throw (Error) entry;
} else {
throw new InternalError("unexpected entry: " + entry);
}
}
再进入ObjectStreamClass构造方法。
private ObjectStreamClass(final Class<?> cl) {
this.cl = cl;
//获取了类的一些基本信息
name = cl.getName();
isProxy = Proxy.isProxyClass(cl);
isEnum = Enum.class.isAssignableFrom(cl);
serializable = Serializable.class.isAssignableFrom(cl);
externalizable = Externalizable.class.isAssignableFrom(cl);
Class<?> superCl = cl.getSuperclass();//获取父类类型
superDesc = (superCl != null) ? lookup(superCl, false) : null;//父类存在,接着调用lookup方法,一直向上递归,直到父类为null。
localDesc = this;
if (serializable) {
AccessController.doPrivileged(new PrivilegedAction<Void>() {
public Void run() {
if (isEnum) {
suid = Long.valueOf(0);
fields = NO_FIELDS;
return null;
}
if (cl.isArray()) {
fields = NO_FIELDS;
return null;
}
suid = getDeclaredSUID(cl);//这里获取了serialVersionUID,如果序列化类没有声明将为null。
try {
fields = getSerialFields(cl);//最重要的一点,获取序列化的属性
computeFieldOffsets();
} catch (InvalidClassException e) {
serializeEx = deserializeEx =
new ExceptionInfo(e.classname, e.getMessage());
fields = NO_FIELDS;
}
if (externalizable) {
cons = getExternalizableConstructor(cl);
} else {
cons = getSerializableConstructor(cl);
//如果序列化类重写了writeObject()和readObject()方法。
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);
return null;
}
});
} else {
suid = Long.valueOf(0);
fields = NO_FIELDS;
}
try {
fieldRefl = getReflector(fields, this);
} catch (InvalidClassException ex) {
// field mismatches impossible when matching local fields vs. self
throw new InternalError(ex);
}
if (deserializeEx == null) {
if (isEnum) {
deserializeEx = new ExceptionInfo(name, "enum type");
} else if (cons == null) {
deserializeEx = new ExceptionInfo(name, "no valid constructor");
}
}
for (int i = 0; i < fields.length; i++) {
if (fields[i].getField() == null) {
defaultSerializeEx = new ExceptionInfo(
name, "unmatched serializable field(s) declared");
}
}
initialized = true;
}
接着进入getSerialFields()方法。
private static ObjectStreamField[] getSerialFields(Class<?> cl)
throws InvalidClassException
{
ObjectStreamField[] fields;
if (Serializable.class.isAssignableFrom(cl) &&
!Externalizable.class.isAssignableFrom(cl) &&
!Proxy.isProxyClass(cl) &&
!cl.isInterface())
{
if ((fields = getDeclaredSerialFields(cl)) == null) {
fields = getDefaultSerialFields(cl);//又调用了这里
}
Arrays.sort(fields);//进行升序排列
} else {
fields = NO_FIELDS;
}
return fields;
}
接着进入getDefaultSerialFields()方法。
private static ObjectStreamField[] getDefaultSerialFields(Class<?> cl) {
Field[] clFields = cl.getDeclaredFields();
ArrayList<ObjectStreamField> list = new ArrayList<>();
int mask = Modifier.STATIC | Modifier.TRANSIENT;
//看到了STATIC和TRANSIENT关键词
for (int i = 0; i < clFields.length; i++) {
if ((clFields[i].getModifiers() & mask) == 0) {
//通过这一行代码,过滤掉了被STATIC和TRANSIENT修饰的序列化属性,这是第三个问题的答案!
list.add(new ObjectStreamField(clFields[i], false, true));
}
}
int size = list.size();
return (size == 0) ? NO_FIELDS :
list.toArray(new ObjectStreamField[size]);
}
ObjectStreamClass相关的主要工作基本上也就结束了,在初始化中主要完成了对序列化对象的,基本信息、serialVersionUID、属性的收集;当然也包括往上所有的父类,是一个递归的过程。
我们回到writeObject0()方法中对Serializable数据的写入操作,writeOrdinaryObject(obj, desc, unshared)方法。
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);//写入Object标识
writeClassDesc(desc, false);//写了一些类信息
handles.assign(unshared ? null : obj);
if (desc.isExternalizable() && !desc.isProxy()) {
writeExternalData((Externalizable) obj);
} else {
writeSerialData(obj, desc);//继续调用这个方法
}
} finally {
if (extendedDebugInfo) {
debugInfoStack.pop();
}
}
}
writeOrdinaryObject()方法重点调用了两个方法,writeClassDesc()和writeSerialData();我们先看writeClassDesc()。
private void writeClassDesc(ObjectStreamClass desc, boolean unshared)
throws IOException
{
int handle;
if (desc == null) {
//对象为null,写入null标识
writeNull();
} else if (!unshared && (handle = handles.lookup(desc)) != -1) {
writeHandle(handle);
} else if (desc.isProxy()) {
writeProxyDesc(desc, unshared);
} else {
writeNonProxyDesc(desc, unshared);//一般都会调用这个方法
}
}
进入writeNonProxyDesc()方法。
private void writeNonProxyDesc(ObjectStreamClass desc, boolean unshared)
throws IOException
{
bout.writeByte(TC_CLASSDESC);//写入类元信息标记位
handles.assign(unshared ? null : desc);
if (protocol == PROTOCOL_VERSION_1) {
// do not invoke class descriptor write hook with old protocol
desc.writeNonProxy(this);
} else {
writeClassDescriptor(desc);//重点在这里,写入了类的描述符信息
}
Class<?> cl = desc.forClass();
bout.setBlockDataMode(true);
if (cl != null && isCustomSubclass()) {
ReflectUtil.checkPackageAccess(cl);
}
annotateClass(cl);
bout.setBlockDataMode(false);
bout.writeByte(TC_ENDBLOCKDATA);
writeClassDesc(desc.getSuperDesc(), false);//又调用writeClassDesc(),传入父类初始化了ObjectStreamClass对象,进入递归模式,写入类的描述符信息。
}
进入writeClassDescriptor()方法。
protected void writeClassDescriptor(ObjectStreamClass desc)
throws IOException
{
desc.writeNonProxy(this);
}
又再调用了ObjectStreamClass对象本身的writeNonProxy()方法。
void writeNonProxy(ObjectOutputStream out) throws IOException {
out.writeUTF(name);//写入类名
out.writeLong(getSerialVersionUID());//再次出现serialVersionUID,这里被写入
//判断类类型的标识
byte flags = 0;
if (externalizable) {
flags |= ObjectStreamConstants.SC_EXTERNALIZABLE;
int protocol = out.getProtocolVersion();
if (protocol != ObjectStreamConstants.PROTOCOL_VERSION_1) {
flags |= ObjectStreamConstants.SC_BLOCK_DATA;
}
} else if (serializable) {
flags |= ObjectStreamConstants.SC_SERIALIZABLE;
}
if (hasWriteObjectData) {
flags |= ObjectStreamConstants.SC_WRITE_METHOD;
}
if (isEnum) {
flags |= ObjectStreamConstants.SC_ENUM;
}
//写入类类型标识
out.writeByte(flags);
//写入序列化属性的信息
out.writeShort(fields.length);
for (int i = 0; i < fields.length; i++) {
ObjectStreamField f = fields[i];
out.writeByte(f.getTypeCode());
out.writeUTF(f.getName());
if (!f.isPrimitive()) {
out.writeTypeString(f.getTypeString());
}
}
}
writeNonProxy()方法中,写入了很多信息,我们还需要看一下getSerialVersionUID()方法。
public long getSerialVersionUID() {
// REMIND: synchronize instead of relying on volatile?
if (suid == null) {//如果ObjectStreamClass初始化时,序列化类没有定义SerialVersionUID,那么suid就是null值。
suid = AccessController.doPrivileged(
new PrivilegedAction<Long>() {
public Long run() {
//获取默认的值,所以这就是第2个问题的一部分答案,为什么要在序列类中定义
//SerialVersionUID,因为如果不定义就会默认生产,而这个默认的值很可能就因为类内容的改变而改变。会产
//生什么具体的影响,后面继续分析!
return computeDefaultSUID(cl);
}
}
);
}
return suid.longValue();
}
分析完writeClassDesc()的流程,我们接着分析writeSerialData()方法,写入真正的数据。
private void writeSerialData(Object obj, ObjectStreamClass desc)
throws IOException
{
ObjectStreamClass.ClassDataSlot[] slots = desc.getClassDataLayout();//获取数据布局的ClassDataSlot实例数组
for (int i = 0; i < slots.length; i++) {
ObjectStreamClass slotDesc = slots[i].desc;
//如果序列化对象实现了自己的writeObject()方法,进入if。
if (slotDesc.hasWriteObjectMethod()) {
PutFieldImpl oldPut = curPut;
curPut = null;
SerialCallbackContext oldContext = curContext;
if (extendedDebugInfo) {
debugInfoStack.push(
"custom writeObject data (class "" +
slotDesc.getName() + "")");
}
try {
curContext = new SerialCallbackContext(obj, slotDesc);
bout.setBlockDataMode(true);
slotDesc.invokeWriteObject(obj, this);
bout.setBlockDataMode(false);
bout.writeByte(TC_ENDBLOCKDATA);
} finally {
curContext.setUsed();
curContext = oldContext;
if (extendedDebugInfo) {
debugInfoStack.pop();
}
}
curPut = oldPut;
} else {
defaultWriteFields(obj, slotDesc);//一般都是调用这里
}
}
}
我们先看下如何获取数据布局的ClassDataSlot实例数组的。
ClassDataSlot[] getClassDataLayout() throws InvalidClassException {
// REMIND: synchronize instead of relying on volatile?
if (dataLayout == null) {
dataLayout = getClassDataLayout0();
}
return dataLayout;
}
又调用了getClassDataLayout0()方法。
private ClassDataSlot[] getClassDataLayout0()
throws InvalidClassException
{
ArrayList<ClassDataSlot> slots = new ArrayList<>();
Class<?> start = cl, end = cl;
// locate closest non-serializable superclass
while (end != null && Serializable.class.isAssignableFrom(end)) {
end = end.getSuperclass();
}
HashSet<String> oscNames = new HashSet<>(3);
for (ObjectStreamClass d = this; d != null; d = d.superDesc) {
if (oscNames.contains(d.name)) {
throw new InvalidClassException("Circular reference.");
} else {
oscNames.add(d.name);
}
// search up inheritance hierarchy for class with matching name
String searchName = (d.cl != null) ? d.cl.getName() : d.name;
Class<?> match = null;
for (Class<?> c = start; c != end; c = c.getSuperclass()) {
if (searchName.equals(c.getName())) {
match = c;
break;
}
}
//通过遍历,把所有的ObjectStreamClass对象包装成了ClassDataSlot对象
// add "no data" slot for each unmatched class below match
if (match != null) {
for (Class<?> c = start; c != match; c = c.getSuperclass()) {
slots.add(new ClassDataSlot(
ObjectStreamClass.lookup(c, true), false));
}
start = match.getSuperclass();
}
// record descriptor/class pairing
slots.add(new ClassDataSlot(d.getVariantFor(match), true));
}
// add "no data" slot for any leftover unmatched classes
for (Class<?> c = start; c != end; c = c.getSuperclass()) {
slots.add(new ClassDataSlot(
ObjectStreamClass.lookup(c, true), false));
}
// order slots from superclass -> subclass
Collections.reverse(slots);//调用了reverse反转,所以最顶端的父类ClassDataSlot对象在前。
return slots.toArray(new ClassDataSlot[slots.size()]);
}
把所有的ObjectStremClass对象再封装成了ClassDataSlot对象,并且进行了倒序排列。回到writeSerialData()方法中,继续进入defaultWriteFields()。
private void defaultWriteFields(Object obj, ObjectStreamClass desc)
throws IOException
{
Class<?> cl = desc.forClass();
if (cl != null && obj != null && !cl.isInstance(obj)) {
throw new ClassCastException();
}
desc.checkDefaultSerialize();
int primDataSize = desc.getPrimDataSize();
if (primVals == null || primVals.length < primDataSize) {
primVals = new byte[primDataSize];
}
//获取基本数据类型的实例数据,并存入primVals数组
desc.getPrimFieldValues(obj, primVals);
//写入primVals数组中的数据,所以基本数据类型在这里就直接写入了。
bout.write(primVals, 0, primDataSize, false);
ObjectStreamField[] fields = desc.getFields(false);
Object[] objVals = new Object[desc.getNumObjFields()];
int numPrimFields = fields.length - objVals.length;
//获取未写入的对象数据,存入objVals数组
desc.getObjFieldValues(obj, objVals);
for (int i = 0; i < objVals.length; i++) {
if (extendedDebugInfo) {
debugInfoStack.push(
"field (class "" + desc.getName() + "", name: "" +
fields[numPrimFields + i].getName() + "", type: "" +
fields[numPrimFields + i].getType() + "")");
}
try {
//再调用writeObject0方法,重新进行类型判断,进行不同的写入处理;也是一种递归处理,直到所有数据写入完成
writeObject0(objVals[i],
fields[numPrimFields + i].isUnshared());
} finally {
if (extendedDebugInfo) {
debugInfoStack.pop();
}
}
}
}
到这里,序列化的过程就结束了。
2.反序列化过程
反序列化API调用
ObjectInputStream inputStream = new ObjectInputStream(new FileInputStream(new File(localFile)));
Person person = (Person) inputStream.readObject();//读取文件
初始化构造函数
public ObjectInputStream(InputStream in) throws IOException {
verifySubclass();
bin = new BlockDataInputStream(in);
handles = new HandleTable(10);
vlist = new ValidationList();
// Android-removed: ObjectInputFilter logic, to be reconsidered. http://b/110252929
// serialFilter = ObjectInputFilter.Config.getSerialFilter();
enableOverride = false;//同样关闭了覆盖能力
readStreamHeader();//读取序列化文件头
bin.setBlockDataMode(true);
}
我们看一下readStreamHeader()方法,读取了头信息进行了损坏判断。
protected void readStreamHeader()
throws IOException, StreamCorruptedException
{
short s0 = bin.readShort();
short s1 = bin.readShort();
if (s0 != STREAM_MAGIC || s1 != STREAM_VERSION) {
throw new StreamCorruptedException(
String.format("invalid stream header: %04X%04X", s0, s1));
}
}
下面我们进入关键的readObject()方法。
public final Object readObject()
throws IOException, ClassNotFoundException
{
if (enableOverride) {//初始化设置成了false,不会走。
return readObjectOverride();
}
// if nested read, passHandle contains handle of enclosing object
int outerHandle = passHandle;
try {
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;
} finally {
passHandle = outerHandle;
if (closed && depth == 0) {
clear();
}
}
}
进入readObject0()方法。
private Object readObject0(boolean unshared) throws IOException {
boolean oldMode = bin.getBlockDataMode();
if (oldMode) {
int remain = bin.currentBlockRemaining();
if (remain > 0) {
throw new OptionalDataException(remain);
} else if (defaultDataEnd) {
/*
* Fix for 4360508: stream is currently at the end of a field
* value block written via default serialization; since there
* is no terminating TC_ENDBLOCKDATA tag, simulate
* end-of-custom-data behavior explicitly.
*/
throw new OptionalDataException(true);
}
bin.setBlockDataMode(false);
}
byte tc;//读取数据类型标识
while ((tc = bin.peekByte()) == TC_RESET) {
bin.readByte();
handleReset();
}
depth++;
// Android-removed: ObjectInputFilter logic, to be reconsidered. http://b/110252929
// totalObjectRefs++;
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()方法。
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);
} 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;
}
我们先看下readClassDesc()方法。
private ObjectStreamClass readClassDesc(boolean unshared)
throws IOException
{
byte tc = bin.peekByte();//获取类元信息标记位
ObjectStreamClass descriptor;
switch (tc) {
case TC_NULL:
descriptor = (ObjectStreamClass) readNull();
break;
case TC_REFERENCE:
descriptor = (ObjectStreamClass) readHandle(unshared);
break;
case TC_PROXYCLASSDESC:
descriptor = readProxyDesc(unshared);
break;
case TC_CLASSDESC:
descriptor = readNonProxyDesc(unshared);//会调用这里
break;
default:
throw new StreamCorruptedException(
String.format("invalid type code: %02X", tc));
}
// Android-removed: ObjectInputFilter logic, to be reconsidered. http://b/110252929
// if (descriptor != null) {
// validateDescriptor(descriptor);
// }
return descriptor;
}
进入readNonProxyDesc()方法。
private ObjectStreamClass readNonProxyDesc(boolean unshared)
throws IOException
{
if (bin.readByte() != TC_CLASSDESC) {
throw new InternalError();
}
ObjectStreamClass desc = new ObjectStreamClass();
int descHandle = handles.assign(unshared ? unsharedMarker : desc);
passHandle = NULL_HANDLE;
ObjectStreamClass readDesc = null;
try {
readDesc = readClassDescriptor();//读取存储的序列化类的描述信息
} catch (ClassNotFoundException ex) {
throw (IOException) new InvalidClassException(
"failed to read class descriptor").initCause(ex);
}
Class<?> cl = null;
ClassNotFoundException resolveEx = null;
bin.setBlockDataMode(true);
final boolean checksRequired = isCustomSubclass();
try {
if ((cl = resolveClass(readDesc)) == null) {
resolveEx = new ClassNotFoundException("null class");
} else if (checksRequired) {
ReflectUtil.checkPackageAccess(cl);
}
} catch (ClassNotFoundException ex) {
resolveEx = ex;
}
skipCustomData();
desc.initNonProxy(readDesc, cl, resolveEx, readClassDesc(false));//初始化类描述符
// Android-removed: ObjectInputFilter unsupported - removed filterCheck() call.
// // Call filterCheck on the definition
// filterCheck(desc.forClass(), -1);
handles.finish(descHandle);
passHandle = descHandle;
return desc;
}
readNonProxyDesc()方法,进行了两个非常关键的处理
- 通过调用readClassDescriptor()方法读取了存储的序列化类的描述信息,并初始化了ObjectStreamClass对象,赋值给了readDesc属性;
- 通过调用新创建的ObjectStreamClass对象desc的initNonProxy()方法,进行了初始化; 这里需要区分一下,readDesc局部属性对象是通过readClassDescriptor()方法创建的,而desc属性对象则是新创建的对象再通过initNonProxy()方法进行初始化,我们先看一下readClassDescriptor()方法。
protected ObjectStreamClass readClassDescriptor()
throws IOException, ClassNotFoundException
{
ObjectStreamClass desc = new ObjectStreamClass();
desc.readNonProxy(this);
return desc;
}
创建了一个ObjectStreamClass对象,直接再调用readNonProxy()方法。
void readNonProxy(ObjectInputStream in)
throws IOException, ClassNotFoundException
{
name = in.readUTF();//类名
suid = Long.valueOf(in.readLong());//熟悉吧,序列化写入的serialVersionUID回来了
isProxy = false;
byte flags = in.readByte();
hasWriteObjectData =
((flags & ObjectStreamConstants.SC_WRITE_METHOD) != 0);
hasBlockExternalData =
((flags & ObjectStreamConstants.SC_BLOCK_DATA) != 0);
externalizable =
((flags & ObjectStreamConstants.SC_EXTERNALIZABLE) != 0);
boolean sflag =
((flags & ObjectStreamConstants.SC_SERIALIZABLE) != 0);
if (externalizable && sflag) {
throw new InvalidClassException(
name, "serializable and externalizable flags conflict");
}
serializable = externalizable || sflag;
isEnum = ((flags & ObjectStreamConstants.SC_ENUM) != 0);
if (isEnum && suid.longValue() != 0L) {
throw new InvalidClassException(name,
"enum descriptor has non-zero serialVersionUID: " + suid);
}
int numFields = in.readShort();
if (isEnum && numFields != 0) {
throw new InvalidClassException(name,
"enum descriptor has non-zero field count: " + numFields);
}
fields = (numFields > 0) ?
new ObjectStreamField[numFields] : NO_FIELDS;
for (int i = 0; i < numFields; i++) {
//循环读取序列化属性信息
char tcode = (char) in.readByte();
String fname = in.readUTF();
String signature = ((tcode == 'L') || (tcode == '[')) ?
in.readTypeString() : new String(new char[] { tcode });
try {
fields[i] = new ObjectStreamField(fname, signature, false);
} catch (RuntimeException e) {
throw (IOException) new InvalidClassException(name,
"invalid descriptor for field " + fname).initCause(e);
}
}
computeFieldOffsets();
}
分析完,我们再回过头去看新创建的ObjectStreamClass对象对initNonProxy()方法的调用。
void initNonProxy(ObjectStreamClass model,
Class<?> cl,
ClassNotFoundException resolveEx,
ObjectStreamClass superDesc)
throws InvalidClassException
{
//需要重点标注一下,参数model就是readDesc,cl是传入的序列化类
long suid = Long.valueOf(model.getSerialVersionUID());//获取了序列化类的serialVersionUID()
ObjectStreamClass osc = null;
if (cl != null) {
osc = lookup(cl, true);
if (osc.isProxy) {
throw new InvalidClassException(
"cannot bind non-proxy descriptor to a proxy class");
}
if (model.isEnum != osc.isEnum) {
throw new InvalidClassException(model.isEnum ?
"cannot bind enum descriptor to a non-enum class" :
"cannot bind non-enum descriptor to an enum class");
}
if (model.serializable == osc.serializable &&
!cl.isArray() &&
suid != osc.getSerialVersionUID()) {//重点、重点、重点 ......
//这就是第二个问题答案,serialVersionUID的作用,通过序列化缓存对象的
//serialVersionUID和传入的序列化类的serialVersionUID对比来判断版本是否一致,这
//也是为什么建议自己定义serialVersionUID的原因,避免类的改动导致serialVersionUID的变化而版本冲突报错。
throw new InvalidClassException(osc.name,
"local class incompatible: " +
"stream classdesc serialVersionUID = " + suid +
", local class serialVersionUID = " +
osc.getSerialVersionUID());
}
if (!classNamesEqual(model.name, osc.name)) {
throw new InvalidClassException(osc.name,
"local class name incompatible with stream class " +
"name "" + model.name + """);
}
if (!model.isEnum) {
if ((model.serializable == osc.serializable) &&
(model.externalizable != osc.externalizable)) {
throw new InvalidClassException(osc.name,
"Serializable incompatible with Externalizable");
}
if ((model.serializable != osc.serializable) ||
(model.externalizable != osc.externalizable) ||
!(model.serializable || model.externalizable)) {
deserializeEx = new ExceptionInfo(
osc.name, "class invalid for deserialization");
}
}
}
//初始化参数赋值
this.cl = cl;
this.resolveEx = resolveEx;
this.superDesc = superDesc;
name = model.name;
this.suid = suid;
isProxy = false;
isEnum = model.isEnum;
serializable = model.serializable;
externalizable = model.externalizable;
hasBlockExternalData = model.hasBlockExternalData;
hasWriteObjectData = model.hasWriteObjectData;
fields = model.fields;
primDataSize = model.primDataSize;
numObjFields = model.numObjFields;
if (osc != null) {
localDesc = osc;
writeObjectMethod = localDesc.writeObjectMethod;
readObjectMethod = localDesc.readObjectMethod;
readObjectNoDataMethod = localDesc.readObjectNoDataMethod;
writeReplaceMethod = localDesc.writeReplaceMethod;
readResolveMethod = localDesc.readResolveMethod;
if (deserializeEx == null) {
deserializeEx = localDesc.deserializeEx;
}
cons = localDesc.cons;
}
fieldRefl = getReflector(fields, localDesc);
// reassign to matched fields so as to reflect local unshared settings
fields = fieldRefl.getFields();
initialized = true;
}
我们再回到readOrdinaryObject()方法去看readSerialData()方法,来获取属性数据。
private void readSerialData(Object obj, ObjectStreamClass desc)
throws IOException
{
ObjectStreamClass.ClassDataSlot[] slots = desc.getClassDataLayout();//获取类数据数组
for (int i = 0; i < slots.length; i++) {
ObjectStreamClass slotDesc = slots[i].desc;
if (slots[i].hasData) {
if (obj == null || handles.lookupException(passHandle) != null) {
defaultReadFields(null, slotDesc); // skip field values
} else if (slotDesc.hasReadObjectMethod()) {//如果重写了readObject()方法
SerialCallbackContext oldContext = curContext;
if (oldContext != null)
oldContext.check();
try {
curContext = new SerialCallbackContext(obj, slotDesc);
bin.setBlockDataMode(true);
slotDesc.invokeReadObject(obj, this);
} 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 custom readObject method has cons'ed and
* thrown a new CNFException of its own.
*/
handles.markException(passHandle, ex);
} finally {
curContext.setUsed();
if (oldContext!= null)
oldContext.check();
curContext = oldContext;
// END Android-changed: ThreadDeath cannot cause corruption on Android.
}
/*
* defaultDataEnd may have been set indirectly by custom
* readObject() method when calling defaultReadObject() or
* readFields(); clear it to restore normal read behavior.
*/
defaultDataEnd = false;
} else {
defaultReadFields(obj, slotDesc);//会执行到这里
}
if (slotDesc.hasWriteObjectData()) {
skipCustomData();
} else {
bin.setBlockDataMode(false);
}
} else {
if (obj != null &&
slotDesc.hasReadObjectNoDataMethod() &&
handles.lookupException(passHandle) == null)
{
slotDesc.invokeReadObjectNoData(obj);
}
}
}
}
进入到defaultReadFields()方法中。
private void defaultReadFields(Object obj, ObjectStreamClass desc)
throws IOException
{
Class<?> cl = desc.forClass();
if (cl != null && obj != null && !cl.isInstance(obj)) {
throw new ClassCastException();
}
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);//把基本数据类型的值设置到序列化类中,obj就是传入的序列化类
}
int objHandle = passHandle;
ObjectStreamField[] fields = desc.getFields(false);
Object[] objVals = new Object[desc.getNumObjFields()];
int numPrimFields = fields.length - objVals.length;
//遍历读取对象类型的序列化值
for (int i = 0; i < objVals.length; i++) {
ObjectStreamField f = fields[numPrimFields + i];
objVals[i] = readObject0(f.isUnshared());//递归调用,回到readObject0()再根据不同的数据类型进行处理。
if (f.getField() != null) {
handles.markDependency(objHandle, passHandle);
}
}
if (obj != null) {
desc.setObjFieldValues(obj, objVals);
}
passHandle = objHandle;
}
到这里,反序列化也完成了。
4.序列化和反序列化流程图
5.对问题进行总结
- 实现Serializable序列化接口就是起一个标识作用,无任何实质意义;
- serialVersionUID是用来判断序列化类的版本,重写serialVersionUID是为了防止因为序列化类的变动,导致默认生成的serialVersionUID不一致而冲突报错;
- transient和static修饰的属性会在ObjectStreamClass类初始化时,getDefaultSerialFields()方法中直接过滤掉了;