序列化:把对象转换为字节序列的过程。
反序列化:把字节序列恢复为对象的过程。
主要用于:
- 网络中数据传输,先将对象转换为字节数组,再将字节数组以二进制序列的方式传输
- 对象的存储,通常以文件的形式存储,典型的应用场景为:Web 服务器中 Session 对象的序列化
Serializable
- 一个类要实现序列化和反序列化,必须实现 Serializable 接口
Serializability of a class is enabled by the class implementing the java.io.Serializable interface. Classes that do not implement this interface will not have any of their state serialized or deserialized.
- Serializable 接口没有方法或字段,仅用于标识可序列化的语义
The serialization interface has no methods or fields and serves only to identify the semantics of being serializable.
- 如果一个类实现了 Serializable 接口,那么它的所有子类都可序列化;如果子类实现了 Serializable 接口而父类未实现,那么父类成员变量将不会被序列化
All subtypes of a serializable class are themselves serializable.
- 父类要么实现 Serializable 接口,要么包含一个可访问的无参构造函数;如果未实现序列化接口,并且未包含可访问的无参构造函数,将抛出 InvalidClassException: <Class Full Path>; no valid constructor
java.io.InvalidClassException: com.designpatterns.prototype.serial.Dog; no valid constructor
To allow subtypes of non-serializable classes to be serialized, the subtype may assume responsibility for saving and restoring the state of the supertype's public, protected, and (if accessible) package fields. The subtype may assume this responsibility only if the class it extends has an accessible no-arg constructor to initialize the class's state. It is an error to declare a class Serializable if this is not the case. The error will be detected at runtime.
- 引用类型的成员变量必须实现 Serializable 接口或者用 transient 修饰
- 不支持 Serializable 接口,在序列化时将抛出:NotSerializableException
When traversing a graph, an object may be encountered that does not support the Serializable interface. In this case the NotSerializableException will be thrown and will identify the class of the non-serializable object.
- 声明 serialVersionUID(可选)
serialVersionUID
强烈推荐所有可序列化类显式声明 serialVersionUID,如果未显式声明,将在序列化运行时基于该类的各个层面计算出一个默认值。
默认的serialVersionUID计算对类细节高度敏感,这些细节可能因编译器实现而异,因此在反序列化期间可能导致意外的InvalidClassExceptions。因此,为了保证跨不同java编译器实现的一致的serialVersionUID值,可序列化类必须声明显式的serialVersionUID值。
serialVersionUID声明尽可能使用private修饰符,因为此类声明仅适用于声明 serialVersionUID 字段的类,继承无用。
数组类不能声明显式的serialVersionUID,因此它们始终具有默认的计算值,但是对于数组类,不需要匹配serialVersionUID值。
The serialization runtime associates with each serializable class a version
number, called a serialVersionUID, which is used during deserialization to
verify that the sender and receiver of a serialized object have loaded
classes for that object that are compatible with respect to serialization.
If the receiver has loaded a class for the object that has a different
serialVersionUID than that of the corresponding sender's class, then
deserialization will result in an {@link InvalidClassException}. A
serializable class can declare its own serialVersionUID explicitly by
declaring a field named "serialVersionUID" that must be static,
final, and of type long:
ANY-ACCESS-MODIFIER static final long serialVersionUID = 42L;
If a serializable class does not explicitly declare a serialVersionUID, then
the serialization runtime will calculate a default serialVersionUID value
for that class based on various aspects of the class, as described in the
Java(TM) Object Serialization Specification. However, it is strongly
recommended that all serializable classes explicitly declare
serialVersionUID values, since the default serialVersionUID computation is
highly sensitive to class details that may vary depending on compiler
implementations, and can thus result in unexpected
InvalidClassExceptions during deserialization. Therefore, to
guarantee a consistent serialVersionUID value across different java compiler
implementations, a serializable class must declare an explicit
serialVersionUID value. It is also strongly advised that explicit
serialVersionUID declarations use the private modifier where
possible, since such declarations apply only to the immediately declaring
class--serialVersionUID fields are not useful as inherited members. Array
classes cannot declare an explicit serialVersionUID, so they always have
the default computed value, but the requirement for matching
serialVersionUID values is waived for array classes.
对象序列化(ObjectOutputStream)
ObjectOutputStream.writeObject
enableOverride:
- 通过默认构造函数:ObjectOutputStream() 创建,enableOverride = true;
- 通过构造函数:ObjectOutputStream(OutputStream out) 创建,enableOverride = false;
当 enableOverride = true 时,直接调用 writeObjectOverride(空方法)并退出,即当输入流不存在时,不做任何操作,可以通过扩展 ObjectOutputStream 并重写 writeObjectOverride 自定义处理方式
public final void writeObject(Object obj) throws IOException {
if (enableOverride) {
writeObjectOverride(obj);
return;
}
try {
writeObject0(obj, false);
} catch (IOException ex) {
if (depth == 0) {
writeFatalException(ex);
}
throw ex;
}
}
ObjectOutputStream.writeObject0
- 创建 ObjectStreamClass对象:desc = ObjectStreamClass.lookup(cl, true);
- 如果目标类存在 writeReplace 方法,调用目标类的 writeReplace 方法,用返回对象替代目标对象序列化
desc.invokeWriteReplace(obj)
- 根据 enableReplace 取值调用 ObjectOutputStream.replaceObject 方法
- enableReplace 可通过 enableReplaceObject 方法设置,enableReplaceObject 被 protected 修饰,可通过继承调用(如:MarshalOutputStream)
- replaceObject 直接返回目标对象,即不替换,被 protected 修饰,可通过继承扩展并重写 replaceObject 自定义处理方式
- 根据目标实例类型执行不同的处理,主要关注实现 Serializable 接口的处理方式: writeOrdinaryObject(obj, desc, unshared);
private void writeObject0(Object obj, boolean unshared)
throws IOException
{
boolean oldMode = bout.setBlockDataMode(false);
depth++;
try {
// handle previously written and non-replaceable objects
int h;
if ((obj = subs.lookup(obj)) == null) {
writeNull();
return;
} else if (!unshared && (h = handles.lookup(obj)) != -1) {
writeHandle(h);
return;
} else if (obj instanceof Class) {
writeClass((Class) obj, unshared);
return;
} else if (obj instanceof ObjectStreamClass) {
writeClassDesc((ObjectStreamClass) obj, unshared);
return;
}
// check for replacement object
Object orig = obj;
Class<?> cl = obj.getClass();
ObjectStreamClass desc;
for (;;) {
// REMIND: skip this check for strings/arrays?
Class<?> repCl;
desc = ObjectStreamClass.lookup(cl, true);
if (!desc.hasWriteReplaceMethod() ||
(obj = desc.invokeWriteReplace(obj)) == null ||
(repCl = obj.getClass()) == cl)
{
break;
}
cl = repCl;
}
if (enableReplace) {
Object rep = replaceObject(obj);
if (rep != obj && rep != null) {
cl = rep.getClass();
desc = ObjectStreamClass.lookup(cl, true);
}
obj = rep;
}
// if object replaced, run through original checks a second time
if (obj != orig) {
subs.assign(orig, obj);
if (obj == null) {
writeNull();
return;
} else if (!unshared && (h = handles.lookup(obj)) != -1) {
writeHandle(h);
return;
} else if (obj instanceof Class) {
writeClass((Class) obj, unshared);
return;
} else if (obj instanceof ObjectStreamClass) {
writeClassDesc((ObjectStreamClass) obj, unshared);
return;
}
}
// remaining cases
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());
}
}
} finally {
depth--;
bout.setBlockDataMode(oldMode);
}
}
ObjectOutputStream.enableReplaceObject
为 enableReplace 变量设值,protected 修饰,仅在 ObjectOutputStream 子类 MarshalOutputStream 中被调用
protected boolean enableReplaceObject(boolean enable)
throws SecurityException
{
if (enable == enableReplace) {
return enable;
}
if (enable) {
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
sm.checkPermission(SUBSTITUTION_PERMISSION);
}
}
enableReplace = enable;
return !enableReplace;
}
ObjectOutputStream.writeOrdinaryObject
extendedDebugInfo:可通过 JVM 参数开启 Debug 信息:
-Dsun.io.serialization.extendedDebugInfo=true
- 根据目标类的继承关系决定处理方式
- 如果目标类实现 Externalizable 接口 并且 不属于代理类,执行 writeExternalData,即调用目标类实现自 Externalizable 接口的 writeExternal 方法
- 否则(实现 Serializable 接口),调用 writeSerialData 方法
- 如果目标类定义了 writeObject,通过 ObjectStreamClass.invokeWriteObject 调用目标类 writeObject 方法
- 如果未定义,调用 defaultWriteFields 执行默认的序列化处理
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);
} else {
writeSerialData(obj, desc);
}
} finally {
if (extendedDebugInfo) {
debugInfoStack.pop();
}
}
}
ObjectStreamClass.isProxyClass
判断目标类是否继承自 Proxy,是否在 proxyClassCache 中
- 如果是,则表明目标类为代理类
public static boolean isProxyClass(Class<?> cl) {
return Proxy.class.isAssignableFrom(cl) && proxyClassCache.containsValue(cl);
}
ObjectOutputStream.writeExternalData
直接通过目标类实例调用实现自 Externalizable 接口的 writeExternal 方法
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);
bout.setBlockDataMode(false);
bout.writeByte(TC_ENDBLOCKDATA);
}
} finally {
curContext = oldContext;
if (extendedDebugInfo) {
debugInfoStack.pop();
}
}
curPut = oldPut;
}
ObjectOutputStream.writeSerialData
- 如果目标类存在 writeObject 方法,通过 ObjectStreamClass 反射调用目标类的 writeObject 方法:slotDesc.invokeWriteObject(obj, this);
- 否则,调用 defaultWriteFields 执行默认的序列化方法
private void writeSerialData(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 (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);
}
}
}
反序列化(ObjectInputStream)
ObjectInputStream.readObject
enableOverride:
- 通过默认构造函数:ObjectInputStream() 创建,enableOverride = true;
- 通过构造函数:ObjectInputStream(InputStream out) 创建,enableOverride = false;
当 enableOverride = true 时,直接调用 readObjectOverride(空方法)并退出,即当输入流不存在时,不做任何操作,可以通过扩展 ObjectInputStream 并重写 readObjectOverride 自定义处理方式
public final Object readObject()
throws IOException, ClassNotFoundException
{
if (enableOverride) {
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();
}
}
}
ObjectInputStream.readObject0
根据目标实例真实类型执行不同的处理方法,主要关注 TC_OBJECT:checkResolve(readOrdinaryObject(unshared));
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++;
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);
}
}
ObjectInputStream.readOrdinaryObject
- 根据目标类的继承关系决定处理方式
- 如果目标类实现 Externalizable 接口,调用 readExternalData 方法
- 否则(实现 Serializable 接口),调用 readSerialData 方法
- 如果目标类存在 readResolve 方法,调用目标类的 readResolve 方法,用返回对象替代目标对象反序列化
desc.invokeReadResolve(obj);
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) {
handles.setObject(passHandle, obj = rep);
}
}
return obj;
}
ObjectInputStream.readExternalData
直接调用目标对象的 readExternal 方法
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);
} 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;
}
/*
* At this point, if the externalizable data was not written in
* block-data form and either the externalizable class doesn't exist
* locally (i.e., obj == null) or readExternal() just threw a
* CNFException, then the stream is probably in an inconsistent state,
* since some (or all) of the externalizable data may not have been
* consumed. Since there's no "correct" action to take in this case,
* we mimic the behavior of past serialization implementations and
* blindly hope that the stream is in sync; if it isn't and additional
* externalizable data remains in the stream, a subsequent read will
* most likely throw a StreamCorruptedException.
*/
}
ObjectInputStream.readSerialData
- 如果 ClassDataSlot 有数据
- 如果目标类存在 readObject 方法,通过 ObjectStreamClass 反射调用目标类的 readObject 方法:
slotDesc.invokeReadObject(obj, this);
- 否则,调用 defaultReadFields 执行默认的反序列化
- 如果目标类存在 readObject 方法,通过 ObjectStreamClass 反射调用目标类的 readObject 方法:
- 如果目标类存在 readObjectNoData 方法,通过 ObjectStreamClass 反射调用目标类的 readObjectNoData 方法:
slotDesc.invokeReadObjectNoData(obj);
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()) {
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;
}
/*
* 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);
}
}
}
}
流类描述(ObjectStreamClass)
ObjectStreamClass.lookup
创建 ObjectStreamClass 实例:
entry = new ObjectStreamClass(cl);
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 Constructor
-
创建方法代理:
- private void writeObject(java.io.ObjectOutputStream out) throws IOException
writeObjectMethod = getPrivateMethod(cl, "writeObject", new Class<?>[] { ObjectOutputStream.class }, Void.TYPE);
- private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException;
readObjectMethod = getPrivateMethod(cl, "readObject", new Class<?>[] { ObjectInputStream.class }, Void.TYPE);
- private void readObjectNoData() throws ObjectStreamException;
readObjectNoDataMethod = getPrivateMethod( cl, "readObjectNoData", null, Void.TYPE); hasWriteObjectData = (writeObjectMethod != null);
- ANY-ACCESS-MODIFIER Object writeReplace() throws ObjectStreamException;
writeReplaceMethod = getInheritableMethod( cl, "writeReplace", null, Object.class);
- ANY-ACCESS-MODIFIER Object readResolve() throws ObjectStreamException;
readResolveMethod = getInheritableMethod( cl, "readResolve", null, Object.class);
writeObject / readObject / readObjectNoData 三个方法都是通过 getPrivateMethod 获取,这就是为什么 三个方法必须被 private 修饰的原因。
- private void writeObject(java.io.ObjectOutputStream out) throws IOException
-
获取 非 static 和 非 transient
getSerialFields -> getDeclaredSerialFields -> getDefaultSerialFieldsfields = getSerialFields(cl);
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;
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);
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);
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");
}
}
}
ObjectStreamClass.getSerialFields
获取目标类中需要序列化的字段:
- 先检查目标类是否定义了 ObjectStreamField[] serialPersistentFields 字段,如果存在且不为空,则 serialPersistentFields 中的所有字段将会被序列化
- 如果未定义或字段为空,则获取所有 非 static 和 非 transient 字段序列化/反序列化
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;
}
ObjectStreamClass.getDeclaredSerialFields
获取目标类中 private static final ObjectStreamField[] serialPersistentFields
字段,该字段用于指定哪些类将被序列化:
private static final ObjectStreamField[] serialPersistentFields = {
new ObjectStreamField("attr1", Integer.TYPE),
new ObjectStreamField("attr2", String.class)
};
private static ObjectStreamField[] getDeclaredSerialFields(Class<?> cl)
throws InvalidClassException
{
ObjectStreamField[] serialPersistentFields = null;
try {
Field f = cl.getDeclaredField("serialPersistentFields");
int mask = Modifier.PRIVATE | Modifier.STATIC | Modifier.FINAL;
if ((f.getModifiers() & mask) == mask) {
f.setAccessible(true);
serialPersistentFields = (ObjectStreamField[]) f.get(null);
}
} catch (Exception ex) {
}
if (serialPersistentFields == null) {
return null;
} else if (serialPersistentFields.length == 0) {
return NO_FIELDS;
}
ObjectStreamField[] boundFields =
new ObjectStreamField[serialPersistentFields.length];
Set<String> fieldNames = new HashSet<>(serialPersistentFields.length);
for (int i = 0; i < serialPersistentFields.length; i++) {
ObjectStreamField spf = serialPersistentFields[i];
String fname = spf.getName();
if (fieldNames.contains(fname)) {
throw new InvalidClassException(
"multiple serializable fields named " + fname);
}
fieldNames.add(fname);
try {
Field f = cl.getDeclaredField(fname);
if ((f.getType() == spf.getType()) &&
((f.getModifiers() & Modifier.STATIC) == 0))
{
boundFields[i] =
new ObjectStreamField(f, spf.isUnshared(), true);
}
} catch (NoSuchFieldException ex) {
}
if (boundFields[i] == null) {
boundFields[i] = new ObjectStreamField(
fname, spf.getType(), spf.isUnshared());
}
}
return boundFields;
}
ObjectStreamClass.getDeclaredSUID
获取目标类 ANY-ACCESS-MODIFIER static final serialVersionUID 字段值
private static Long getDeclaredSUID(Class<?> cl) {
try {
Field f = cl.getDeclaredField("serialVersionUID");
int mask = Modifier.STATIC | Modifier.FINAL;
if ((f.getModifiers() & mask) == mask) {
f.setAccessible(true);
return Long.valueOf(f.getLong(null));
}
} catch (Exception ex) {
}
return null;
}
ObjectStreamClass.getSerialVersionUID
获取目标类 serialVersionUID,如果未定义,计算生成默认的 serialVersionUID
public long getSerialVersionUID() {
// REMIND: synchronize instead of relying on volatile?
if (suid == null) {
suid = AccessController.doPrivileged(
new PrivilegedAction<Long>() {
public Long run() {
return computeDefaultSUID(cl);
}
}
);
}
return suid.longValue();
}
ObjectStreamClass.computeDefaultSUID
计算默认的 serialVersionUID
- 未实现 Serializable 接口、代理生成类,直接返回 0L
- serialVersionUID 生成相关:
- 类的访问修饰符与类名
- 方法的访问修饰符与方法名
- 类实现的接口与接口名
- 字段修饰符与字段名
- 构造函数
- SHA 算法
private static long computeDefaultSUID(Class<?> cl) {
if (!Serializable.class.isAssignableFrom(cl) || Proxy.isProxyClass(cl))
{
return 0L;
}
try {
ByteArrayOutputStream bout = new ByteArrayOutputStream();
DataOutputStream dout = new DataOutputStream(bout);
dout.writeUTF(cl.getName());
int classMods = cl.getModifiers() &
(Modifier.PUBLIC | Modifier.FINAL |
Modifier.INTERFACE | Modifier.ABSTRACT);
/*
* compensate for javac bug in which ABSTRACT bit was set for an
* interface only if the interface declared methods
*/
Method[] methods = cl.getDeclaredMethods();
if ((classMods & Modifier.INTERFACE) != 0) {
classMods = (methods.length > 0) ?
(classMods | Modifier.ABSTRACT) :
(classMods & ~Modifier.ABSTRACT);
}
dout.writeInt(classMods);
if (!cl.isArray()) {
/*
* compensate for change in 1.2FCS in which
* Class.getInterfaces() was modified to return Cloneable and
* Serializable for array classes.
*/
Class<?>[] interfaces = cl.getInterfaces();
String[] ifaceNames = new String[interfaces.length];
for (int i = 0; i < interfaces.length; i++) {
ifaceNames[i] = interfaces[i].getName();
}
Arrays.sort(ifaceNames);
for (int i = 0; i < ifaceNames.length; i++) {
dout.writeUTF(ifaceNames[i]);
}
}
Field[] fields = cl.getDeclaredFields();
MemberSignature[] fieldSigs = new MemberSignature[fields.length];
for (int i = 0; i < fields.length; i++) {
fieldSigs[i] = new MemberSignature(fields[i]);
}
Arrays.sort(fieldSigs, new Comparator<MemberSignature>() {
public int compare(MemberSignature ms1, MemberSignature ms2) {
return ms1.name.compareTo(ms2.name);
}
});
for (int i = 0; i < fieldSigs.length; i++) {
MemberSignature sig = fieldSigs[i];
int mods = sig.member.getModifiers() &
(Modifier.PUBLIC | Modifier.PRIVATE | Modifier.PROTECTED |
Modifier.STATIC | Modifier.FINAL | Modifier.VOLATILE |
Modifier.TRANSIENT);
if (((mods & Modifier.PRIVATE) == 0) ||
((mods & (Modifier.STATIC | Modifier.TRANSIENT)) == 0))
{
dout.writeUTF(sig.name);
dout.writeInt(mods);
dout.writeUTF(sig.signature);
}
}
if (hasStaticInitializer(cl)) {
dout.writeUTF("<clinit>");
dout.writeInt(Modifier.STATIC);
dout.writeUTF("()V");
}
Constructor<?>[] cons = cl.getDeclaredConstructors();
MemberSignature[] consSigs = new MemberSignature[cons.length];
for (int i = 0; i < cons.length; i++) {
consSigs[i] = new MemberSignature(cons[i]);
}
Arrays.sort(consSigs, new Comparator<MemberSignature>() {
public int compare(MemberSignature ms1, MemberSignature ms2) {
return ms1.signature.compareTo(ms2.signature);
}
});
for (int i = 0; i < consSigs.length; i++) {
MemberSignature sig = consSigs[i];
int mods = sig.member.getModifiers() &
(Modifier.PUBLIC | Modifier.PRIVATE | Modifier.PROTECTED |
Modifier.STATIC | Modifier.FINAL |
Modifier.SYNCHRONIZED | Modifier.NATIVE |
Modifier.ABSTRACT | Modifier.STRICT);
if ((mods & Modifier.PRIVATE) == 0) {
dout.writeUTF("<init>");
dout.writeInt(mods);
dout.writeUTF(sig.signature.replace('/', '.'));
}
}
MemberSignature[] methSigs = new MemberSignature[methods.length];
for (int i = 0; i < methods.length; i++) {
methSigs[i] = new MemberSignature(methods[i]);
}
Arrays.sort(methSigs, new Comparator<MemberSignature>() {
public int compare(MemberSignature ms1, MemberSignature ms2) {
int comp = ms1.name.compareTo(ms2.name);
if (comp == 0) {
comp = ms1.signature.compareTo(ms2.signature);
}
return comp;
}
});
for (int i = 0; i < methSigs.length; i++) {
MemberSignature sig = methSigs[i];
int mods = sig.member.getModifiers() &
(Modifier.PUBLIC | Modifier.PRIVATE | Modifier.PROTECTED |
Modifier.STATIC | Modifier.FINAL |
Modifier.SYNCHRONIZED | Modifier.NATIVE |
Modifier.ABSTRACT | Modifier.STRICT);
if ((mods & Modifier.PRIVATE) == 0) {
dout.writeUTF(sig.name);
dout.writeInt(mods);
dout.writeUTF(sig.signature.replace('/', '.'));
}
}
dout.flush();
MessageDigest md = MessageDigest.getInstance("SHA");
byte[] hashBytes = md.digest(bout.toByteArray());
long hash = 0;
for (int i = Math.min(hashBytes.length, 8) - 1; i >= 0; i--) {
hash = (hash << 8) | (hashBytes[i] & 0xFF);
}
return hash;
} catch (IOException ex) {
throw new InternalError(ex);
} catch (NoSuchAlgorithmException ex) {
throw new SecurityException(ex.getMessage());
}
}
ObjectStreamClass.getDefaultSerialFields
获取目标类中所有的 非 static 和 非 transient 属性
private static ObjectStreamField[] getDefaultSerialFields(Class<?> cl) {
Field[] clFields = cl.getDeclaredFields();
ArrayList<ObjectStreamField> list = new ArrayList<>();
int mask = Modifier.STATIC | Modifier.TRANSIENT;
for (int i = 0; i < clFields.length; i++) {
if ((clFields[i].getModifiers() & mask) == 0) {
list.add(new ObjectStreamField(clFields[i], false, true));
}
}
int size = list.size();
return (size == 0) ? NO_FIELDS :
list.toArray(new ObjectStreamField[size]);
}
ObjectStreamClass.invokeWriteObject
反射调用目标类 writeObject 方法
/**
* Invokes the writeObject method of the represented serializable class.
* Throws UnsupportedOperationException if this class descriptor is not
* associated with a class, or if the class is externalizable,
* non-serializable or does not define writeObject.
*/
void invokeWriteObject(Object obj, ObjectOutputStream out)
throws IOException, UnsupportedOperationException
{
if (writeObjectMethod != null) {
try {
writeObjectMethod.invoke(obj, new Object[]{ out });
} catch (InvocationTargetException ex) {
Throwable th = ex.getTargetException();
if (th instanceof IOException) {
throw (IOException) th;
} else {
throwMiscException(th);
}
} catch (IllegalAccessException ex) {
// should not occur, as access checks have been suppressed
throw new InternalError(ex);
}
} else {
throw new UnsupportedOperationException();
}
}
ObjectStreamClass.invokeReadObject
反射调用目标类 readObject 方法
/**
* Invokes the readObject method of the represented serializable class.
* Throws UnsupportedOperationException if this class descriptor is not
* associated with a class, or if the class is externalizable,
* non-serializable or does not define readObject.
*/
void invokeReadObject(Object obj, ObjectInputStream in)
throws ClassNotFoundException, IOException,
UnsupportedOperationException
{
if (readObjectMethod != null) {
try {
readObjectMethod.invoke(obj, new Object[]{ in });
} catch (InvocationTargetException ex) {
Throwable th = ex.getTargetException();
if (th instanceof ClassNotFoundException) {
throw (ClassNotFoundException) th;
} else if (th instanceof IOException) {
throw (IOException) th;
} else {
throwMiscException(th);
}
} catch (IllegalAccessException ex) {
// should not occur, as access checks have been suppressed
throw new InternalError(ex);
}
} else {
throw new UnsupportedOperationException();
}
}
ObjectStreamClass.invokeReadObjectNoData
反射调用目标类 readObjectNoData 方法
/**
* Invokes the readObjectNoData method of the represented serializable
* class. Throws UnsupportedOperationException if this class descriptor is
* not associated with a class, or if the class is externalizable,
* non-serializable or does not define readObjectNoData.
*/
void invokeReadObjectNoData(Object obj)
throws IOException, UnsupportedOperationException
{
if (readObjectNoDataMethod != null) {
try {
readObjectNoDataMethod.invoke(obj, (Object[]) null);
} catch (InvocationTargetException ex) {
Throwable th = ex.getTargetException();
if (th instanceof ObjectStreamException) {
throw (ObjectStreamException) th;
} else {
throwMiscException(th);
}
} catch (IllegalAccessException ex) {
// should not occur, as access checks have been suppressed
throw new InternalError(ex);
}
} else {
throw new UnsupportedOperationException();
}
}
ObjectStreamClass.invokeWriteReplace
反射调用目标类 writeReplace 方法
/**
* Invokes the writeReplace method of the represented serializable class and
* returns the result. Throws UnsupportedOperationException if this class
* descriptor is not associated with a class, or if the class is
* non-serializable or does not define writeReplace.
*/
Object invokeWriteReplace(Object obj)
throws IOException, UnsupportedOperationException
{
if (writeReplaceMethod != null) {
try {
return writeReplaceMethod.invoke(obj, (Object[]) null);
} catch (InvocationTargetException ex) {
Throwable th = ex.getTargetException();
if (th instanceof ObjectStreamException) {
throw (ObjectStreamException) th;
} else {
throwMiscException(th);
throw new InternalError(th); // never reached
}
} catch (IllegalAccessException ex) {
// should not occur, as access checks have been suppressed
throw new InternalError(ex);
}
} else {
throw new UnsupportedOperationException();
}
}
ObjectStreamClass.invokeReadResolve
Externalizable
继承自 Serializable,接口定义了两个方法:
public interface Externalizable extends java.io.Serializable {
void writeExternal(ObjectOutput out) throws IOException;
void readExternal(ObjectInput in) throws IOException, ClassNotFoundException;
}
总结
Serializable
- 保存 serialPersistentFields 指定字段 或 非 static 非 transient 的成员变量
- 无需实现任何方法,可通过内部默认实现,序列化/反序列化类中所有符合要求的字段
- 可重写 writeObject、readObject、readObjectNoData、writeReplace、readResolve 等方法自定实现,指定需要序列化/反序列化的字段
- 可通过以下方式对特定字段进行特殊处理:
- transient + writeObject / defaultWriteObject
- transient + readObject / defaultReadObject
Externalizable
- 必须实现 writeExternal、readExternal 接口方法,在实现方法中指定需要序列化/反序列化的字段
- transient 在实现类中无效