什么是序列化和反序列化,不得不说一开始看到这个略显高级的词,就被吓到了,心想这是个啥玩意呢。不过去查阅资料,一步步自习斟酌,最终也将揭开他们的面纱。
**序列化:**简单来讲就是对象转换为二进制字节序列的一个过程,而二进制字节序列就是
**反序列化:**就是将序列化反过来,将二进制字节序列转换为对象。
这样转换来转换去有啥意义呢,我们知道对象是保存到内存中的,而在对象序列化之后,我们可以将对象存储到文件当中,然后以便永久保存到磁盘上,等你需要用的时候直接反序列化出来到内存中。更重要的是,序列化之后可以用于在网络上进行传输,像什么文本,图片,视频的都是要先序列化为字节序列再进行传送的。
(打个比方:平时用微信聊天,你发送一张图片或表情包是要先转化为二进制数据,这样数据就可以存储在本地,然后通过网络协议传输到腾讯服务器,然后服务器又将该二进制数据传输到好友的微信客户端,最后客户端又将该二进制转数据换为图片,对方也就接收到了。)
序列化和反序列化的实现:
实现序列化,先要将该类实现Serializable接口,之后该类的所有方法和属性都可以进行序列化
下面将展现最常见的序列化方式:即创建字节流和对象流,并定义readObject方法和writeObject方法。
先创建一个Hero类,并将该类实现Serializable接口:
import java.io.Serializable;
public class Hero implements Serializable {
final static long serialVersionsUID = 1L;//设置版本号
public String name ;
public Hero(String name){
this.name=name;
}
}
然后我再分别创建序列化测试类和反序列化测试类:
序列化测试类:
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
public class Test_serialize {
public static void main(String[] args) throws IOException {
File file = new File("D:\\桌面\\IDEA实验室\\读取.txt");
Hero hero = new Hero("动力小子" );//创建一个Hero对象
FileOutputStream fos = new FileOutputStream(file);
ObjectOutputStream oos = new ObjectOutputStream(fos);
System.out.println(hero.name);
oos.writeObject(hero);//序列化到文件中
oos.close();
fos.close();
}
}
将对象序列化到文件中,并输出了动力小子
反序列化测试类:
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
public class Test_Deserialize {
public static void main(String[] args) throws IOException, ClassNotFoundException {
File file = new File("D:\\桌面\\IDEA实验室\\读取.txt");
FileInputStream fis = new FileInputStream(file);
ObjectInputStream ois = new ObjectInputStream(fis);
Hero hero = new Hero("非动力小子");
hero =(Hero)ois.readObject();//创建一个对象接收反序列化过来的对象
System.out.println(hero.name);
ois.close();
fis.close();
}
}
可以看到反序列化测试中,我创建了一个对象名为 “不是动力小子” ,如果反序列化失败了,说明没有接收到文件中返还过来的对象,输出就是 “非动力小子” ,如果反序列化成功了,输出的就是动力小子。
Hero类中的serialVersionsUID是这个序列化类的版本号,每次进行反序列化时都会对该版本号进行检查(如果没有自己手动设置,jvm会默认设置一个版本号),每次序列化后如果对Hero类中的属性和非私有方法进行增添,删除或者修改,都会改变这个类版本号,再进行反序列化就会报错,如图:
先序列化,然后添加一个属性:
然后反序列化,报错:
其中第一句说:
local class incompatible: stream classdesc serialVersionUID = -7007252755224453746, local class serialVersionUID = 4876276661417299199
意思就是是本地类的UID和字节流传过来的UID不一致,为避免这种情况,一定要先更改再序列化然后反序列化。
当然如果有些属性你不想序列化,则使用 transient 关键字修饰。如图:
这样子这个变量就自己是一家了,别的变量跟着去序列化了他在内存里歇着,别的变量都反序列化回来了他还是歇着。