Java序列化和反序列化

基础

序列化:将数据结构或对象转换成二进制串的过程。
反序列化:将在序列化过程中所生成的二进制串转换成数据结构或者对象的过程。
调用writeObject()序列化一个对象,是将其写入磁盘,以后在程序再次调用readObject()时,根据wirteObject()磁盘的文件重新恢复那个对象。
Externalizable接口扩展Serializable,并增添两个方法:writeExternal()readExternal()。在序列化和重新装配的过程中,会自动调用这两个方法。
ExternalizableSerializable接口的子类,有时不希望序列化那么多,可以使用这个接口,这个接口的writeExternal()readExternal()可以指定序列化哪些属性。

算法

算法一般会按步骤做如下事情:

  1. 将对象实例相关的类元数据输出。
  2. 递归地输出类的超类描述直到不再有超类。
  3. 类元数据完以后,开始从最顶层的超类开始输出对象实例的实际数据值。
  4. 从上至下递归输出实例的数据。

    使用场景

    语言里增加对象序列化的概念后,可提供对两种主要特性的支持。
  • 远程方法调用(RMI)使本来存在于其他机器的对象可以表现出好象就在本地机器上的行为。将消息发给远程对象时,需要通过对象序列化来传输参数和返回值。
  • 使用一个Java Bean时,它的状态信息通常在设计期间配置好。程序启动以后,这种状态信息必须保存下来,以便程序启动以后恢复;具体工作由对象序列化完成。

    字节码解析

    保存对象序列化字节码
    1
    2
    3
    4
    5
    6
    7
    8
    9
    package demo1;

    import java.io.Serializable;

    class Parent implements Serializable {
    private static final long serialVersionUID = 1L;

    int parentVersion = 10;
    }
1
2
3
4
5
6
7
8
9
package demo1;

import java.io.Serializable;

public class Contain implements Serializable{
private static final long serialVersionUID = 1L;

int containVersion = 11;
}
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
package demo1;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.io.Serializable;

/**
*
* 序列化字节码
*
*/
public class SerialTest extends Parent implements Serializable {
private static final long serialVersionUID = 1L;

int version = 66;
Contain con = new Contain();

public int getVersion() {
return version;
}

//序列化
public static void main(String args[]) throws IOException {
File file=new File("D:\\temp.out");
if(!file.exists()){
file.createNewFile();
}
FileOutputStream fos = new FileOutputStream(file);
ObjectOutputStream oos = new ObjectOutputStream(fos);
SerialTest st = new SerialTest();
oos.writeObject(st);
oos.flush();
oos.close();
}
}

反序列化

1
2
3
4
5
6
7
8
9
public static void main(String[] args) throws IOException, ClassNotFoundException {
File file=new File("D:\\temp.out");
FileInputStream fis = new FileInputStream(file);
ObjectInputStream ois = new ObjectInputStream(fis);
SerialTest st1 = (SerialTest) ois.readObject();
System.out.println("getVersion():"+st1.getVersion());
ois.close();
fis.close();
}

控制台输出

1
getVersion():66

temp.out输出

1
2
3
4
5
6
7
8
9
10
AC ED 00 05 73 72 00 0A 53 65 72 69 61 6C 54 65
73 74 05 52 81 5A AC 66 02 F6 02 00 02 49 00 07
76 65 72 73 69 6F 6E 4C 00 03 63 6F 6E 74 00 09
4C 63 6F 6E 74 61 69 6E 3B 78 72 00 06 70 61 72
65 6E 74 0E DB D2 BD 85 EE 63 7A 02 00 01 49 00
0D 70 61 72 65 6E 74 56 65 72 73 69 6F 6E 78 70
00 00 00 0A 00 00 00 42 73 72 00 07 63 6F 6E 74
61 69 6E FC BB E6 0E FB CB 60 C7 02 00 01 49 00
0E 63 6F 6E 74 61 69 6E 56 65 72 73 69 6F 6E 78
70 00 00 00 0B

字节码分析

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
40
41
42
43
44
45
AC ED:STREAM_MAGIC。声明使用序列化协议。
00 05:STREAM_VERSION。序列化协议版本。
0x73:TC_OBJECT。声明这是一个新的对象。
0x72:TC_CLASSDESC。 声明这里开始一个新Class。
00 0A:Class名字的长度。
53 65 72 69 61 6c 54 65 73 74:SerialTest,Class类名。
05 52 81 5A AC 66 02 F6:SerialVersionUID,序列化ID,如果没有指定,则会由算法随机生成一个8byte的ID。
0x02:标记号。该值声明该对象支持序列化。
00 02:该类所包含的域个数。
0x49:域类型。49 代表"I",也就是Int。
00 07:域名字的长度。
76 65 72 73 69 6F 6E:version,域名字描述。
0x4C:域的类型。
00 03:域名字长度。
63 6F 6E:域名字描述,con。
0x74:TC_STRING。代表一个new String,用String来引用对象。
00 09:该String长度。
4C 63 6F 6E 74 61 69 6E 3B:Lcontain;JVM的标准对象签名表示法。
0x78:TC_ENDBLOCKDATA,对象数据块结束的标志。
0x72:TC_CLASSDESC。声明这个是个新类。
00 06:类名长度。
70 61 72 65 6E 74:parent,类名描述。
0E DB D2 BD 85 EE 63 7A:SerialVersionUID,序列化ID。
0x02: 标记号. 该值声明该对象支持序列化。
00 01: 类中域的个数。
0x49:域类型. 49 代表"I",也就是Int。
00 0D:域名字长度。
70 61 72 65 6E 74 56 65 72 73 69 6F 6E:parentVersion,域名字描述。
0x78:TC_ENDBLOCKDATA,对象块结束的标志。
0x70:TC_NULL,说明没有其他超类的标志。
00 00 00 0A:10,parentVersion域的值。
00 00 00 42:66, version域的值。
0x73:TC_OBJECT,声明这是一个新的对象。
0x72:TC_CLASSDESC声明这里开始一个新Class。
00 07:类名的长度。
63 6F 6E 74 61 69 6E:contain,类名描述。
FC BB E6 0E FB CB 60 C7:SerialVersionUID,序列化ID。
0x02:Various flags. 标记号。该值声明该对象支持序列化。
00 01:类内的域个数。
0x49:域类型. 49 代表"I",也就是Int..
00 0E:域名字长度。
63 6F 6E 74 61 69 6E 56 65 72 73 69 6F 6E:containVersion,域名字描述。
0x78:TC_ENDBLOCKDATA对象块结束的标志。
0x70:TC_NULL,没有超类。
00 00 00 0B:11,containVersion的值。


字节分类意义

字节 说明
AC-73 输出对象相关类的描述。
72-02 SerialTest类的描述。
49-6E int version=66。
4C-78 contain con = new contain();这个有点特殊,是个对象。描述对象类型引用时需要使用JVM的标准对象签名表示法。
72-70 输出parent类的域描述,int parentVersion=100。
00-42 实例对象的实际值,Parent类,SerialTest类。
73-0B 描述contain类的信息,要记住,现在还没有对contain类进行过描述。

源码解析

ObjectOutputStream

objectOutputStream#writeObject(obj)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
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;
}
}

writeObject(obj)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
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;
}
}

writeObject0(Object obj, boolean unshared)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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());
}
}

从上可以看出,如果对象没有实现Serializable接口,在序列化的时候会抛出NotSerializableException异常。
上述SerialTest是一个类对象,所以会执行writeOrdinaryObject(obj, desc, unshared)
writeOrdinaryObject(obj, desc, unshared)

1
2
3
4
5
if (desc.isExternalizable() && !desc.isProxy()) {
writeExternalData((Externalizable) obj);
} else {
writeSerialData(obj, desc);
}

如果对象实现Externalizable接口,那么执行writeExternalData((Externalizable) obj)
如果对象实现的是Serializable接口,那么执行的是writeSerialData(obj, desc)
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
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);
}
}

如果没有默认writer(),执行defaultWriteFields()
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
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];
}
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();
}
}
}
}

writeExternalData()

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
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;
}

在此方法中 obj.writeExternal(this) 执行序列化对象实现的writeExternal

ObjectInputStream

objectInputStream#readObject()

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
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#readObject()执行readObject0(false)
readObject0(false)

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
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
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);
}

根据不同的对象类型做相应的处理,这里关注的是TC_OBJECT,执行的方法是checkResolve(readOrdinaryObject(unshared));
readOrdinaryObject()加载序列化对象的Class,如果可以实例化,那么创建它的实例desc.newInstance()
readOrdinaryObject()

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
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
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;
}

# Java

评论

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×