Serializable序列化使用

原文地址 blog.csdn.net

好像一般不用jdk提供的序列化方式,故这里仅为了解
另外Externalizable接口也可以实现序列化

1
2
3
public interface Externalizable extends java.io.Serializable {
...
}

Serializable接口

自定义 writeObject 方法和 readObject 方法

如果在实现 Serializable 接口的类中自定义 writeObject 方法和 readObject 方法,则不会调用默认的方法:

先调用WriteReplace()替换,再调用WriteObject… 反射实现

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
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
public class ObjectStreamClass implements Serializable {
// ....
private Method writeObjectMethod;
private Method writeReplaceMethod;
// ....


writeObjectMethod = getPrivateMethod(cl, "writeObject",
new Class<?>[] { ObjectOutputStream.class },
Void.TYPE);
writeReplaceMethod = getInheritableMethod(
cl, "writeReplace", null, Object.class);
}

// Default serialization for a class can be overridden using the writeObject and the readObject methods.
public class ObjectOutputStream
extends OutputStream implements ObjectOutput, ObjectStreamConstants{

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

private void writeObject0(Object obj, boolean unshared)
throws IOException
{
// ...

// 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 || //调用对象的WriteReplace方法,替换当前对象
(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;
}


// .....
else if (obj instanceof Serializable) {
writeOrdinaryObject(obj, desc, unshared);
}
}

//Method:writeOrdinaryObject
if (desc.isExternalizable() && !desc.isProxy()) {
writeExternalData((Externalizable) obj);
} else {
writeSerialData(obj, desc);//here
}

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()) {


try {
curContext = new SerialCallbackContext(obj, slotDesc);
bout.setBlockDataMode(true);
slotDesc.invokeWriteObject(obj, this);// WriteObject()写入对象
bout.setBlockDataMode(false);
bout.writeByte(TC_ENDBLOCKDATA);
} finally {
curContext.setUsed();
curContext = oldContext;
if (extendedDebugInfo) {
debugInfoStack.pop();
}
}

curPut = oldPut;
} else {
defaultWriteFields(obj, slotDesc);
}
}
}

}

示例

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
package serializable;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;


public class Student implements Serializable {
private static final long serialVersionUID = 140932343675039705L;

private String name;

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

@Override
public String toString(){
return "学生:" + name;
}

private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
System.out.println("readObject exec...");
}

private void writeObject(ObjectOutputStream out) throws IOException{
System.out.println("writeObject exec...");
}

public static void main(String[] args) throws IOException, ClassNotFoundException {
Student student = new Student();
student.setName("小明");
String filePath = "/Users/dcc/Downloads/student";
ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(filePath));
out.writeObject(student);
out.close();

ObjectInputStream in = new ObjectInputStream(new FileInputStream(filePath));
Student student1 = (Student) in.readObject();
System.out.println(student1);
}

}

程序输出结果:

1
2
3
writeObject exec...
readObject exec...
学生:null

因为在 writeObject 方法中只打印了日志,没有序列化 name 字段,所以 readObject 方法没有反序列化出 name. 可以在自定义的 writeObject 方法和 readObject 方法中调用默认方法:

1
2
3
4
5
6
7
8
9
private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
in.defaultReadObject();
System.out.println("readObject exec...");
}

private void writeObject(ObjectOutputStream out) throws IOException{
out.defaultWriteObject();
System.out.println("writeObject exec...");
}

修改之后 name 字段序列化和反序列化均成功,程序输出:

1
2
3
writeObject exec...
readObject exec...
学生:小明

writeReplace 方法和 readResolve 方法

writeReplace 方法可以替换序列化的对象;readResolve 方法是替换反序列化的对象:

看如下代码:

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
61
62
63
package serializable;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.ObjectStreamException;
import java.io.Serializable;


public class Student implements Serializable {
private static final long serialVersionUID = 140932343675039705L;

private String name;

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

@Override
public String toString(){
return "学生:" + name;
}

private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
in.defaultReadObject();
System.out.println("readObject exec...");
}

private void writeObject(ObjectOutputStream out) throws IOException{
out.defaultWriteObject();
System.out.println("writeObject exec...");
}

private Object writeReplace() throws ObjectStreamException{
System.out.println("writeReplace exec...");
return this;
}

private Object readResolve() throws ObjectStreamException{
System.out.println("readResolve exec...");
return this;
}

public static void main(String[] args) throws IOException, ClassNotFoundException {
Student student = new Student();
student.setName("小明");
String filePath = "/Users/dcc/Downloads/student";
ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(filePath));
out.writeObject(student);
out.close();

ObjectInputStream in = new ObjectInputStream(new FileInputStream(filePath));
Student teacher = (Student) in.readObject();
System.out.println(teacher);
}

}

程序运行结果:

1
2
3
4
5
writeReplace exec...
writeObject exec...
readObject exec...
readResolve exec...
学生:小明

可以看出:writeReplace 方法是在 writeObject 方法之前执行;readResolve 方法是在 readResolve 方法之后执行。

修改上面的代码:

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
package serializable;

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;


public class Teacher implements Serializable {
private static final long serialVersionUID = 4644753740588166024L;

private String teacherNo;

public Teacher(String teacherNo) {
this.teacherNo = teacherNo;
}

@Override
public String toString() {
return "老师:" + teacherNo;
}

private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
in.defaultReadObject();
System.out.println("Teacher readObject exec...");
}

private void writeObject(ObjectOutputStream out) throws IOException{
out.defaultWriteObject();
System.out.println("Teacher writeObject exec...");
}
}
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
public class Student implements Serializable {
private static final long serialVersionUID = 140932343675039705L;

private String name;

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

@Override
public String toString(){
return "学生:" + name;
}

private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
in.defaultReadObject();
System.out.println("readObject exec...");
}

private void writeObject(ObjectOutputStream out) throws IOException{
out.defaultWriteObject();
System.out.println("writeObject exec...");
}

private Object writeReplace() throws ObjectStreamException{
System.out.println("writeReplace exec...");
return new Teacher("007");//替换为老师对象,之后通过反射调用老师的writeObject方法
}

public static void main(String[] args) throws IOException, ClassNotFoundException {
Student student = new Student();
student.setName("小明");
String filePath = "/Users/dcc/Downloads/student";
ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(filePath));
out.writeObject(student);
out.close();

ObjectInputStream in = new ObjectInputStream(new FileInputStream(filePath));
Student student1 = (Student) in.readObject();
System.out.println(student1);
}

}

程序输出:

1
2
3
4
5
writeReplace exec...
Teacher writeObject exec...
Teacher readObject exec...
Exception in thread "main" java.lang.ClassCastException: serializable.Teacher cannot be cast to serializable.Student
at serializable.Student.main(Student.java:57)

可以看到序列化的小明同学 Student 对象已经被 writeReplace 方法替换成了 Teacher 对象,而且执行的是 Teacher 类中定义的 writeObject 方法和 readObject 方法。

源码,ok

反序列化处代码修改:

1
2
3
ObjectInputStream in = new ObjectInputStream(new FileInputStream(filePath));
Teacher teacher = (Teacher) in.readObject();
System.out.println(teacher);

程序输出结果:

1
2
3
4
writeReplace exec...
Teacher writeObject exec...
Teacher readObject exec...
老师:007

我们在 Student 类中增加 readResolve 方法:

1
2
3
4
private Object readResolve() throws ObjectStreamException{
System.out.println("readResolve exec...");
return new Teacher("001");
}

此时反序列化得到的老师对象仍是 “老师: 007” 而不是“老师: 001”,因为反序列化出的是 Teacher 对象,不会调用 StudentreadResolve 方法。

我们接着在 Teacher 类中添加 readResolve 方法:

1
2
3
4
private Object readResolve() throws ObjectStreamException{
System.out.println("Teacher readResolve exec...");
return new Teacher("001");
}

此时序列化得到的老师对象才是 “老师: 001”。

我们把 Student 和 Teacher 类中的 writeObject 方法、 readObject 方法、writeReplace 方法和、readResolve 方法四种方法都补齐,看一下调用顺序:

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
package serializable;

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.ObjectStreamException;
import java.io.Serializable;


public class Teacher implements Serializable {
private static final long serialVersionUID = 4644753740588166024L;

private String teacherNo;

public Teacher(String teacherNo) {
this.teacherNo = teacherNo;
}

@Override
public String toString() {
return "老师:" + teacherNo;
}

private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
in.defaultReadObject();
System.out.println("Teacher readObject exec...");
}

private void writeObject(ObjectOutputStream out) throws IOException{
out.defaultWriteObject();
System.out.println("Teacher writeObject exec...");
}

private Object writeReplace() throws ObjectStreamException {
System.out.println("Teacher writeReplace exec...");
return this;
}

private Object readResolve() throws ObjectStreamException{
System.out.println("Teacher readResolve exec...");
return new Teacher("001");
}
}
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
61
62
package serializable;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.ObjectStreamException;
import java.io.Serializable;

public class Student implements Serializable {
private static final long serialVersionUID = 140932343675039705L;

private String name;

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

@Override
public String toString(){
return "学生:" + name;
}

private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
in.defaultReadObject();
System.out.println("readObject exec...");
}

private void writeObject(ObjectOutputStream out) throws IOException{
out.defaultWriteObject();
System.out.println("writeObject exec...");
}

private Object writeReplace() throws ObjectStreamException{
System.out.println("writeReplace exec...");
return new Teacher("007");
}

private Object readResolve() throws ObjectStreamException{
System.out.println("readResolve exec...");
return new Teacher("001");
}

public static void main(String[] args) throws IOException, ClassNotFoundException {
Student student = new Student();
student.setName("小明");
String filePath = "/Users/dcc/Downloads/student";
ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(filePath));
out.writeObject(student);
out.close();

ObjectInputStream in = new ObjectInputStream(new FileInputStream(filePath));
Teacher teacher = (Teacher) in.readObject();
System.out.println(teacher);
}

}

程序输出结果:

1
2
3
4
5
6
writeReplace exec...
Teacher writeReplace exec...
Teacher writeObject exec...
Teacher readObject exec...
Teacher readResolve exec...
老师:001
-------------再接再厉更进一步---------------