测试之前:先明白什么是序列化和反序列化
把对象转化为字节序列的过程成为序列化;
把字节序列恢复为对象的过程成为反序列化;
对象的序列化主要有两种用途:
1) 把对象的字节序列永久地保存到硬盘上,通常存放在一个文件中;
2) 在网络上传送对象的字节序列。
在很多应用中,需要对某些对象进行序列化,让它们离开内存空间,入住物理硬盘,以便长期保存。比如最常见的是Web服务器中的Session对象,当有 10万用户并发访问,就有可能出现10万个Session对象,内存可能吃不消,于是Web容器就会把一些seesion先序列化到硬盘中,等要用了,再把保存在硬盘中的对象还原到内存中。
当两个进程在进行远程通信时,彼此可以发送各种类型的数据。无论是何种类型的数据,都会以二进制序列的形式在网络上传送。发送方需要把这个Java对象转换为字节序列,才能在网络上传送;接收方则需要把字节序列再恢复为Java对象。
将要序列的类
import java.io.Serializable;
public class Person implements Serializable{
private static final long serialVersionUID = 4603642343377807742L;
private int age;
private String name;
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
测试类:
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.text.MessageFormat;
public class TestObjSerializeAndDeserialize {
public static void main(String[] args) throws Exception {
SerializePerson();//序列化Person对象
// Person p = DeserializePerson();//反序列Perons对象
// System.out.println(MessageFormat.format("name={0},age={1}",
// p.getName(), p.getAge()));
}
private static void SerializePerson() throws FileNotFoundException, IOException {
Person person = new Person();
person.setName("gacl");
person.setAge(25);
// ObjectOutputStream 对象输出流,将Person对象存储到E盘的Person.txt文件中,完成对Person对象的序列化操作
ObjectOutputStream oo = new ObjectOutputStream(new FileOutputStream(new File("E:/Person.txt")));
oo.writeObject(person);
System.out.println("Person对象序列化成功!");
oo.close();
}
private static Person DeserializePerson() throws Exception, IOException {
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(new File("E:/Person.txt")));
Person person = (Person) ois.readObject();
System.out.println("Person对象反序列化成功!");
return person;
}
}
测试一:
1、先将反序列代码注掉,进行序列化,序列化成功
2、修改Person的serialVersionUID的值,然后注掉序列化代码,进行反序列化,则会报错Exception in thread "main" java.io.InvalidClassException: com.Person; local class incompatible: stream classdesc serialVersionUID = 4603642343377807741, local class serialVersionUID = 4603642343377807742
测试一结论:
说明serialVersionUID 的值在序列化和反序列化时如果不一样,反序列化则会出错
测试二:
1、Person类不变,测试类的序列化和反序列化代码都放开,则会发现序列化和反序列化都成功
测试二结论:
说明serialVersionUID 的值一直保持一直,反序列就不会被影响
测试三:
在测试2的基础上,不变serialVersionUID 的值,修改Person类,为它添加新的字段,仍然发现序列化和反序列化都成功。
测试三结论:
说明只要serialVersionUID 的值序列和反序列化时保持一直,被序列化的类被更新了同样可以反序列化
测试四:
1、在Person里面不定义private static final long serialVersionUID = 4603642343377807742L;
2、Person保持不变
3、测试类的序列化和反序列化代码都放开,序列化和反序列化都成功
测试四结论:
不更改要被序列化的类时,serialVersionUID的值默认序列化时和反序列化时是一致的
测试五:
1、先序列化原有类Person的对象,并成功
2、在测试四的基础上修改Person的类,为Person添加一个字段
private String tel;
public String getTel() {
return tel;
}
public void setTel(String tel) {
this.tel = tel;
}
3、再反序列化,发现报错
Exception in thread "main" java.io.InvalidClassException: com.Person; local class incompatible: stream classdesc serialVersionUID = 3388821027241830783, local class serialVersionUID = -5201602265694021977
测试五结论:
如果要反序列化的类在序列化之前反序列化之后进行了修改。serialVersionUID 会发生变化,导致反序列失败
总结:
开发中每个 实体对象都实现了序列化接口Serializable,而且需要定义serialVersionUID的变量并给出确定的值,因为在开发中实体类的修改是无法避免的事
序列化的作用是能转化成byte流,然后又能反序列化成原始的类。能在网络进行传输,也可以保存在磁盘中,有了SUID之后,那么如果序列化的类已经保存在本地,中途你修改了类后,SUID变了,那么反序列化的时候就不会变成原始的类了,还会抛出异常。主要用于版本控制
我发现我见过的所有项目(数据库层都是用的mybatis),所有的实体都会实现Serializable接口,如果不实现该接口,对数据库的操作就会报错。所以我判定只要是数据库层用的是mybatis,实体都要实现Serializable接口。跟一个外公司的师父讨论了下,他也没注意这个问题,看了一下他们的代码,果真实现了Serializable接口。开心,学到了一点点