详解Java 序列化与反序列化
观前提示:
本文所使用的Eclipse版本为Photon Release (4.8.0),IDEA版本为ultimate 2019.1,JDK版本为1.8.0_141,Tomcat版本为9.0.12。
1.基本概念
1.1 定义
序列化:把对象转换为字节序列的过程称为对象的序列化。
反序列化:把字节序列恢复为对象的过程称为对象的反序列化。
1.2 用途
-
把对象的字节序列永久地保存到硬盘上,通常存放在一个文件中。
-
在网络上传送对象的字节序列。
2.实现序列化和反序列化
2.1 JDK类库中序列化API
JDK中关键类 ObjectOutputStream(对象输出流) 和 ObjectInputStream(对象输入流)
ObjectOutputStream 类:通过使用 writeObject(Object object) 方法,将对象以二进制格式进行写入。
ObjectInputStream 类:通过使用 readObject()方法,从输入流中读取二进制流,转换成对象。
2.2 实现Serializable接口
这个对象的所有属性(包括private属性、包括其引用的对象)都可以被序列化和反序列化来保存、传递。不想序列化的字段可以使用transient修饰。
例子如下
实现Serializable接口的Person.java
package testSerialize;
import java.io.Serializable;
public class Person implements Serializable {
private static final long serialVersionUID = 1351786752651948395L;
private String id;
private String name;
private transient int age;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
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;
}
@Override
public String toString() {
return "Person{" +
"id='" + id + '\'' +
", name='" + name + '\'' +
", age=" + age +
'}';
}
}
测试类Test.java
package testSerialize;
import java.io.*;
public class Test {
public static void main(String[] args){
// 序列化
Person person = new Person();
person.setId("123456");
person.setName("张三");
person.setAge(18);
// ObjectOutputStream输出流,将Person对象存储到文件中,实现序列化
ObjectOutputStream os = null;
try {
os = new ObjectOutputStream(new FileOutputStream("D:test.txt"));
os.writeObject(person);
os.close();
} catch (Exception e){
e.printStackTrace();
} finally {
if (os != null){
try {
os.close();
} catch (Exception e){
}
}
}
System.out.println("--------------------序列化完成--------------------");
// 反序列化
ObjectInputStream is = null;
try {
is = new ObjectInputStream(new FileInputStream("D:test.txt"));
Person p = (Person) is.readObject();
System.out.println(p.toString());
} catch (Exception e){
e.printStackTrace();
} finally {
if (is != null){
try {
is.close();
} catch (Exception e){
}
}
}
System.out.println("--------------------反序列化完成--------------------");
}
}
运行结果如下
保存文件内容为我们看不懂的序列化后的东西
注意
-
Serializable 接口的作用只是用来标识我们这个类是需要进行序列化,并且 Serializable 接口中并没有提供任何方法。
-
SerialVersionUid 序列化版本号的作用是用来区分我们所编写的类的版本,用于判断反序列化时类的版本是否一直,如果不一致会出现版本不一致异常。
-
transient 关键字,主要用来忽略我们不希望进行序列化的变量
2.3 实现Externalizable 接口
它是Serializable接口的子类,用户要实现的==writeExternal()和readExternal() ==方法,用来决定如何序列化和反序列化。