0%

java关于对象序列化的总结

定义

对象序列化,就是将Object转换成byte序列,反之叫对象的反序列化.

  • 序列化流(ObjectOutputStream),是过滤流—-writeObject
  • 反序列化流(ObjectInputStream)—-readObject

序列化接口(Serializable)

对象必须实现序列化接口 ,才能进行序列化,否则将出现异常
这个接口,没有任何方法,只是一个标准.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
String file = "demo/obj.dat";
//1.对象的序列化
ObjectOutputStream oos = new ObjectOutputStream(
new FileOutputStream(file));
Student stu = new Student("10001", "张三", 20);
oos.writeObject(stu);
oos.flush();
oos.close();
//2.对象的反序列化
ObjectInputStream ois = new ObjectInputStream(
new FileInputStream(file));
Student stu = (Student)ois.readObject();
System.out.println(stu);
ois.close();

transient关键字

transient修饰的变量不会进行jvm默认的序列化,但可以自己完成这个元素的序列化.即覆写:

1
2
3
4
 private void writeObject(java.io.ObjectOutputStream s)
throws java.io.IOException
private void readObject(java.io.ObjectInputStream s)
throws java.io.IOException, ClassNotFoundException
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 String stuno;
private String stuname;
//该元素不会进行jvm默认的序列化,也可以自己完成这个元素的序列化
private transient int stuage;

public Student(String stuno, String stuname, int stuage) {
super();
this.stuno = stuno;
this.stuname = stuname;
this.stuage = stuage;
}

public String getStuno() {
return stuno;
}
public void setStuno(String stuno) {
this.stuno = stuno;
}
public String getStuname() {
return stuname;
}
public void setStuname(String stuname) {
this.stuname = stuname;
}
public int getStuage() {
return stuage;
}
public void setStuage(int stuage) {
this.stuage = stuage;
}
@Override
public String toString() {
return "Student [stuno=" + stuno + ", stuname=" + stuname + ", stuage="
+ stuage + "]";
}
private void writeObject(java.io.ObjectOutputStream s)
throws java.io.IOException{
s.defaultWriteObject();//把jvm能默认序列化的元素进行序列化操作
s.writeInt(stuage);//自己完成stuage的序列化
}
private void readObject(java.io.ObjectInputStream s)
throws java.io.IOException, ClassNotFoundException{
s.defaultReadObject();//把jvm能默认反序列化的元素进行反序列化操作
this.stuage = s.readInt();//自己完成stuage的反序列化操作
}
}

ArrayList源码中对elementData数组序列化和反序列化的处理,因为elementData数组中不是所有元素都是有效元素,所以只序列化了size个有效元素.
在这里插入图片描述
在这里插入图片描述

序列化中 子父类构造函数的调用问题

一个类实现了序列化接口,那么其子类都可以进行序列化.
子类对象进行反序列化操作时,如果其父类没有实现序列化接口,那么其父类的构造函数会被调用.

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
public class ObjectSeriaDemo2 {
public static void main(String[] args) throws Exception{
//序列化Foo2
ObjectOutputStream oos = new ObjectOutputStream(
new FileOutputStream("demo/obj1.dat"));
Foo2 foo2 = new Foo2();
oos.writeObject(foo2);
oos.flush();
oos.close();

//反序列化Foo2是否递归调用父类的构造函数?不会调用Foo1(),Foo()
ObjectInputStream ois = new ObjectInputStream(
new FileInputStream("demo/obj1.dat"));
Foo2 foo2 = (Foo2)ois.readObject();
System.out.println(foo2);
ois.close();

//序列化Bar2
ObjectOutputStream oos = new ObjectOutputStream(
new FileOutputStream("demo/obj1.dat"));
Bar2 bar2 = new Bar2();
oos.writeObject(bar2);
oos.flush();
oos.close();

//反序列化Bar2是否递归调用父类的构造函数?会调用Bar1(),Bar()
ObjectInputStream ois = new ObjectInputStream(
new FileInputStream("demo/obj1.dat"));
Bar2 bar2 = (Bar2)ois.readObject();
System.out.println(bar2);
ois.close();


/*
* 对子类对象进行反序列化操作时,
* 如果其父类没有实现序列化接口
* 那么其父类的构造函数会被调用
*/
}
}
/*
* 一个类实现了序列化接口,那么其子类都可以进行序列化
*/
class Foo implements Serializable{
public Foo(){
System.out.println("foo...");
}
}
class Foo1 extends Foo{
public Foo1(){
System.out.println("foo1...");
}
}
class Foo2 extends Foo1{
public Foo2(){
System.out.println("foo2...");
}
}
class Bar{
public Bar(){
System.out.println("bar");
}
}
class Bar1 extends Bar{
public Bar1(){
System.out.println("bar1..");
}
}
class Bar2 extends Bar1 implements Serializable{
public Bar2(){
System.out.println("bar2...");
}
}