#1.序列化与反序列化的概念
将对象转换为字节序列的过程称为对象的序列化。
反过来,将字节序列恢复成对象的过程称为对象的反序列化。
#2.为什么要将对象序列化?
2.1当我们需要将内存中的对象保存到一个文件中/数据库中的时候
通常我们需要将某些对象进行序列化,让它离开内存空间,入驻物理硬盘,以便长期保存,需要的时候在调取它。例如:缓存,我们需要将缓存存储起来,需要的时候再将它取出来。
2.2需要在网络上传送对象的时候
当两个进程在进行远程通信时,彼此时间需要发送数据,无论哪种类型的数据,都会以二进制序列的形式在网络上传送。
#3.如何实现对象序列化?
很简单,将需要序列化的类实现Serializable接口即可,Serializable接口中没有任何方法。将它理解为一个标记,即表明这个类可以序列化。
#4.实现序列化原理
java.io.ObjectOutputStream表示对象输出流,writeObject(Object obj)方法将指定对象obj写入一个输出流中,即对该对象进行序列化。
java.io.ObjectInputStream表示对象输入流,readObject()方法从ObjectInputStream读取字节序列,再将它们反序列化成为一个对象,并将其返回。
只有实现了Serializable接口的类才能被序列化。对象序列化步骤:
1>创建一个对象输出流,即ObjectOutputStream,它可以包装一个目标输出流,例如文件输出流。
2>调用writeObject(Object obj)方法,参数为obj
对象反序列化过程:
1>创建一个对象输入流,即ObjectInputStream,它可以包装一个源输入流,例如文件输入流。
2>调用readObject()方法读取对象
#5.实例
5.1 定义一个User类并实现Serializable
public class User implements Serializable{
//序列化id
private static final long serialVersionUID = 1L;
private Integer id;
private String name;
}
5.2序列化与反序列化User对象
public class TestSerializable {
public static void main(String[] args) throws InstantiationException, IllegalAccessException, ClassNotFoundException {
//序列化对象
SerializeUser();
//反序列化
User user = DeSerializeUser();
System.out.println(user);
}
}
序列化对象代码
/**
* 序列化User对象
* 1>创建一个对象输出流,即ObjectOutputStream,它可以包装一个目标输出流,例如文件输出流。
* 2>调用writeObject(Object obj)方法,参数为obj
* @throws IllegalAccessException
* @throws InstantiationException
*/
private static void SerializeUser() throws InstantiationException, IllegalAccessException{
//运用反射创建User对象
User user = new User();
try {
Class<?> clazz = Class.forName("com.test.spring.bean.User");
user = (User) clazz.newInstance();
user.setId(1001);
user.setName("张三");
} catch (ClassNotFoundException e1) {
System.out.println("没有找到该类");
e1.printStackTrace();
}
//创建对象输出流
//将User对象序列化,并存储到E盘的Test文件下User.txt文件中
ObjectOutputStream oos = null;
try {
oos = new ObjectOutputStream(new FileOutputStream(new File("E:\\Test\\User.txt")));
oos.writeObject(user);
System.out.println("对象序列化成功");
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}finally {
try {
oos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
反序列化代码
/**
* 反序列化User对象
* 1>创建一个对象输入流,即ObjectInputStream,它可以包装一个源输入流,例如文件输入流。
* 2>调用readObject()方法读取对象
* @throws ClassNotFoundException
*/
private static User DeSerializeUser() throws ClassNotFoundException{
//new方式创建对象
User user = new User();
ObjectInputStream ois = null;
try {
ois = new ObjectInputStream(new FileInputStream(new File("E:\\Test\\User.txt")));
user = (User) ois.readObject();
System.out.println("对象反序列化成功");
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally {
try {
ois.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
return user;
}
#6.serialVersionUID
serialVersionUID是序列化版本号,所有实现Serializable接口的类都需要有一个表示序列化版本标识符。
那这个serialVersionUID有什么用呢?
1.我们去掉User类中的serialVersionUID
2.在序列化这个类
3.在User类中添加新的属性
4.再反序列化User类
报错信息如下
java.io.InvalidClassException: com.test.spring.bean.User; local class incompatible: stream classdesc serialVersionUID = 5057804141597769629, local class serialVersionUID = -2824417979782532292
反序列化的过程中出现问题,报错是stream classdesc serialVersionUID与local class serialVersionUID不一致。
在User类中,如果我们没有指定serialVersionUID,则java编译器会自动给该类添加一个serialVersionUID;由于没有显式的指定serialVersionUID,所有我们修改了User类之后,编译器又会给我们指定一个serialVersionUID,这就出现了两个序列化版本号不一致的错误。
接着测试下有serialVersionUID的情况
1.加上serialVersionUID
2.序列化对象
3.修改对象字段
4.直接反序列化对象
测试了(假设新增属性为age),证明可以反序列化成功,结果如下
对象反序列化成功
User [id=1001, name=张三, age=null]