IO-06-序列化和反序列化

IO-序列化和反序列化

1. 什么是序列化和反序列化?

  • 序列化:把堆内存上的Java对象数据,通过某种方式把对象存储到磁盘文件中或者传递给其他网络节点。这个过程称为序列化,通俗来说就是将数据结构或者对象转换成二进制串的过程。

  • 反序列化:把磁盘文件中的对象数据或者把网络节点上的对象数据,恢复成Java对象模型的过程。也就是将在序列化过程中所产生的二进制串转换成数据结构或者对象的过程。

2. 为什么要做序列化?

  • 在分布式的系统中,此时需要把对象在网络上传输,就是得把对象转换成二进制的形式。如需要共享的JavaBean对象,都得做序列化。
  • 服务器钝化:
    • 如果服务器发现某些对象好久没有活动了,那么服务器就会把这些内存中的对象持久化到本地磁盘文件中(Java对象转换成二进制文件);
    • 如果服务器发现某些对象需要活动的时候,先去内存中寻找,找不到再去磁盘文件中反序列化我们的对象数据,恢复成Java对象,这样能节省服务器内存。

3. Java如何进行序列化?

  1. 需要做序列化的对象的类,必须实现序列化接口:Java.lang.Serializable 接口(这是一个标志接口,没有任何抽象方法),Java 中大多数类都实现了该接口,比如:String,Integer
  2. 底层会判断,如果当前对象是Serializable 的实例,才允许做序列化,(Java对象 instance of Serializable 来判断)
  3. 在Java中使用对象流来完成序列化和反序列化
    • ObjectOutputStream:通过 writeObject()方法做序列化操作
    • ObjectInputStream:通过 readObject() 方法做反序列化操作

mark

实例演示:

  1. 第一步:创建一个JavaBean对象
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
import java.io.Serializable;

public class Person implements Serializable {
private String name;
private int age;

public String getName() {
return name;
}

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

public int getAge() {
return age;
}

public void setAge(int age) {
this.age = age;
}

public Person(String name, int age) {
this.name = name;
this.age = age;
}

@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
  1. 第二步:使用ObjectOutputStream对象来实现序列化
1
2
3
4
5
6
7
8
9
10
11
12
13
14
import java.io.*;

public class Serlize {
public static void main(String[] args) throws IOException {
OutputStream op = new FileOutputStream("io" + File.separator + "a.txt");

// 序列化对象
ObjectOutputStream ops = new ObjectOutputStream(op);

// 序列化操作
ops.writeObject(new Person("vue",1));
ops.close();
}
}
  • 我们打开 a.txt 文件,发现里面的内容乱码,
  • 注意这不需要我们来看懂,这是二进制文件,计算机能读懂就行了。

注意事项:

  • 如果新建的 Person 对象没有实现 Serializable 接口,那么上面的操作会报错:

mark

  1. 第三步:使用ObjectInputStream 来进行反序列化

需要注意的:

  • 反序列化的对象必须要提供该对象的字节码文件.class
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import java.io.*;

public class UnSerlize {
public static void main(String[] args) throws IOException, ClassNotFoundException {
FileInputStream in = new FileInputStream("io" + File.separator + "a.txt");

// 反序列化对象
ObjectInputStream os = new ObjectInputStream(in);
Person p = (Person) os.readObject();

// 读取操作
byte[] buffer = new byte[10];
int len = -1;
System.out.println(p);

// 关闭资源
os.close();
}
}

可以看到结果是:

1
Person{name='vue', age=1}

4. 问题总结

  1. 如果某些数据不需要做序列化(比如密码,年龄)
    • 解决方案:在字段前加上transient
1
2
private String name;//需要序列化
transient private int age;//不需要序列化

那么我们在反序列化的时候,打印出来的就是Person [name=vae, age=0],整型数据默认值为 0

  1. 序列化版本的问题,在完成序列化之后,由于项目的升级或者修改,可能我们会对序列化对象进行修改,比如增加某个字段,那么在反序列化上就会报错

比如在上面的Person类中加入一个字段:

1
2
3
private String name;
private int age;
private int id;

报错:

mark

解决方案:在JavaBean中增加一个 serialVersionUID 字段,用来固定这个版本,无论我们怎么修改,版本都是一致的,就能进行反序列化了

1
private static final long serialVersionUID = 678397537617897505L;
打赏
  • 版权声明: 本博客所有文章除特别声明外,均采用 Apache License 2.0 许可协议。转载请注明出处!
  • © 2019-2022 Zhuuu
  • PV: UV:

请我喝杯咖啡吧~

支付宝
微信