背景
实现Serializable接口就能把对象序列化反序列化出去,那么原理是什么呢?
带着以下问题一探究竟
- 为什么实现这个接口就能序列化和反序列化呢?
- 序列化和反序列化的内容是什么呢,可以自定义吗?
为什么实现这个接口就能序列化和反序列化呢
- java序列化代码
1
2
3
4
5
6
7
8
9public static void main(String[] args) throws IOException {
Object o = new Serializable() {
String strValue = "这是内容";
Integer intValue = 999;
};
File file = new File(System.getProperty("java.io.tmpdir"), "serializable/");
ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream(file));
objectOutputStream.writeObject(o);
}
这样就会把对象序列化到指定的文件中,我们点开writeObject方法看源码一探究竟
1 |
|
所以要想[反]序列化对象,类型必须是String|array|enum|Serializable|class,不然就会直接报错
writeOrdinaryObject
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21private void writeOrdinaryObject(Object obj,
ObjectStreamClass desc,
boolean unshared)
throws IOException
{
try {
bout.writeByte(TC_OBJECT);
writeClassDesc(desc, false);
handles.assign(unshared ? null : obj);
// 实现java.io.Externalizable接口,可自定义[反]序列化的内容
if (desc.isExternalizable() && !desc.isProxy()) {
writeExternalData((Externalizable) obj);
} else {
writeSerialData(obj, desc);
}
} finally {
if (extendedDebugInfo) {
debugInfoStack.pop();
}
}
}writeSerialData
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40private 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;
// 当前对象[反]序列化工具类的包装,
// 如果没有实现java.io.Externalizable自定义[反]序列化接口也没关系
// 直接把writeObject(序列化)和readObject(反序列化)名称写在你自己的类当中,也可以自定义[反]序列化的内容哦
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);
}
}
}如果类中有writeReplace方法,则会调用,并且序列化的目标类为该方法的返回值
defaultWriteFields
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40private 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];
}
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(objVals[i],
fields[numPrimFields + i].isUnshared());
} finally {
if (extendedDebugInfo) {
debugInfoStack.pop();
}
}
}
}
总结
除基本类型和String、Enum、class和array外,其他类型想要[反]序列化,必须实现Serializable接口,不然直接报错
自定义[反]序列化内容有两种方法,一是直接写方法(writeObject(序列化)|readObject(反序列化))到自己的类中,二是实现java.io.Externalizable接口.
writeObject参数类型是ObjectOutputStream
readObject参数类型是ObjectInputStream
方法返回类型必须为void,private,非staticwriteReplace返回值为Object类型的方法,可自定义真正序列化的对象
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 老曹的私房站!
评论