Java序列化原理
概念
- Java序列化是把Java对象转换为字节序列的过程。
- Java反序列化是指把字节序列恢复为Java对象的过程。
实现
- 借助Java提供的API:java.io.ObjectOutputStream(对象输出流)和java.io.ObjectInputStream(对象输入流)。
- 待序列化的实体类要实现Serializable或Externalizable接口。
try {
// serializable为文件名称
FileOutputStream fileOutputStream = new FileOutputStream("serializable");
ObjectOutputStream objectOutputStream = new ObjectOutputStream(fileOutputStream);
// 待序列化的对象
Student student = new Student(18, 0);
// 写入文件
objectOutputStream.writeObject(student);
objectOutputStream.flush();
objectOutputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
try {
FileInputStream fileInputStream = new FileInputStream("serializable");
ObjectInputStream objectInputStream = new ObjectInputStream(fileInputStream);
Student student = (Student) objectInputStream.readObject();
System.out.println(student.toString());
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
}
原理
以序列化为例,从实现入手,首先我们需要构造一个对象输出流:
ObjectOutputStream objectOutputStream = new ObjectOutputStream(fileOutputStream);
ObjectOutputStream
public ObjectOutputStream(OutputStream out) throws IOException {
// 验证是否是ObjectInputStream的子类
verifySubclass();
// BlockDataOutputStream内部类, 存放数据字节的容器
bout = new BlockDataOutputStream(out);
// HandleTable是Serializable中的缓存池,在序列化或者反序列化是,当遇到同一种信息时,如果缓存池中有缓存信息,则可以减少很多不必要的解析,引用到缓存池的那个信息即可
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;
}
}
接着,我们使用objectOutputStream.writeObject(student)
输出待序列化的对象,关于其源码如下:
public final void writeObject(Object obj) throws IOException {
// 当实例化ObjectOutputStream对象时, 采用的是ObjectOutputStream的无参构造方法
// enableOverride会被设置为true, writeObjectOverride方法在ObjectOutputStream中
// 没有提供具体实现, 需要我们通过继承然后重写这个方法
if (enableOverride) {
writeObjectOverride(obj);
return;
}
try {
// 以本文new ObjectOutputStream(fileOutputStream)为例子, 会执行这个方法进行输出
writeObject0(obj, false);
} catch (IOException ex) {
if (depth == 0) {
writeFatalException(ex);
}
throw ex;
}
}
writeObjectOverride方法如下:
protected void writeObjectOverride(Object obj) throws IOException {
}
writeObject0
writeObject0方法如下:
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) {
// handles为HandleTable对象, 存放缓存信息
// 如果handles找到obj,说明已经被解析过,不需要重复解析
writeHandle(h);
return;
} else if (obj instanceof Class) {
// Class类型的处理方式
writeClass((Class) obj, unshared);
return;
} else if (obj instanceof ObjectStreamClass) {
// 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;
// 通过ObjectStreamClass.lookup拿到类型描述信息
desc = ObjectStreamClass.lookup(cl, true);
if (!desc.hasWriteReplaceMethod() ||
(obj = desc.invokeWriteReplace(obj)) == null ||
(repCl = obj.getClass()) == cl)
{
// 如果描述信息中没有实现writeReplace()方法
// 或者实现了writeReplace()替换对象的方法,但返回了空对象
// 或者实现了writeReplace()替换对象的方法, 但返回的类型实际和待序列化的类 类型一样
break;
}
// 继续循环, 拿到真正的对象的类信息
cl = repCl;
}
if (enableReplace) {
// 如果允许替换对象会通过replaceObject方法拿到真正的对象
// replaceObject方法默认返回obj, 如果想要替换该对象, 可重写该方法
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);
}
}
writeOrdinaryObject
writeOrdinaryObject 方法如下:
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);
// 默认情况为false, 表示对象描述可以被缓存复用
handles.assign(unshared ? null : obj);
if (desc.isExternalizable() && !desc.isProxy()) {
// 实现了Externalizable时的序列化方式
writeExternalData((Externalizable) obj);
} else {
// 实现了Serializable的序列化方式
writeSerialData(obj, desc);
}
} finally {
if (extendedDebugInfo) {
debugInfoStack.pop();
}
}
}
writeSerialData
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()) {
// 如果对象重写了writeObject()方法则进入到这里
// ......
} else {
// 默认走这里进行序列化
defaultWriteFields(obj, slotDesc);
}
}
}
defaultWriteFields
private void defaultWriteFields(Object obj, ObjectStreamClass desc)
throws IOException
{
Class<?> cl = desc.forClass();
// 做类型校验,保证从Obj获得的对象描述正确
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];
}
// 反射获取属性值
desc.getPrimFieldValues(obj, primVals);
bout.write(primVals, 0, primDataSize, false);
ObjectStreamField[] fields = desc.getFields(false);
Object[] objVals = new Object[desc.getNumObjFields()];
int numPrimFields = fields.length - objVals.length;
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();
}
}
}
}
总结
其实整个序列化过程,就是一个递归的过程,在defaultWriteFields方法中,通过反射的方式解析出对象、属性等的描述,如果属性为对象,继续writeObject0调用。