Java|Java序列化和反序化

一、什么是序列化和反序列化 Java序列化就是指把Java对象转换为字节序列的过程
Java反序列化就是指把字节序列恢复为Java对象的过程。
二、为什么要把一个对象序列化 正常情况下,Java new出的对象,是保存在内存当中的,是不能持久化保存的,也不能直接在网络中传输,如何解决呢?就是把Java对象转换为byte字节数据,以字节的方式去实现持久化保存和网络传输。而反序列化,就是把须列化后的数据,重新恢复成内存中的Java对象。
总之,序列化,就是对一个Java对象的保存和重建的过程。
三、Java实现序列化的过程 为了让一个Java对象能序列化,我们需要为这个Java对象实现Serializable接口,像下面这样,这个方法和普通的Bean来说,多继承了这个接口,这个接口没有实现实现任何方法,它是为什么告诉编译器,这个接口可以序列化。

@Data public class User implements Serializable {private String name; private int age; private Stringsex; private String phone; }

这个类可以序列化了,但如何序列化让它能本地存储呢?执行下面的write方法,将会在D盘根目录下创建User类的序列化文件,执行read方法可以把序列化文件转变成对象。
public class Client {@Test public void write() throws Exception{ User user = new User(); user.setAge(15); user.setName("张三"); user.setPhone("123"); FileOutputStream fileOutputStream = new FileOutputStream("D://out.txt"); ObjectOutputStream objectOutputStream = new ObjectOutputStream(fileOutputStream); objectOutputStream.writeObject(user); }@Test public void read() throws Exception{ FileInputStream fileInputStream = new FileInputStream("D://out.txt"); ObjectInputStream objectInputStream = new ObjectInputStream(fileInputStream); User o = (User)objectInputStream.readObject(); System.out.println(o.toString()); }}

read方法运行结果,序列化出来的对象,拥有序列化之前对象的值。
Java|Java序列化和反序化
文章图片

四、不能被序列化的对象 Java对象中,如果一个字段被transient修饰,或者这个字段是static静态字段,这个类将不会被序列化,意味着,这个对象被序列化后,再次反序列化成Java对象后,对于的字段值为null。
Java|Java序列化和反序化
文章图片

五、序列号的作用 我们的类是不断的变动的,我们把一个对象序列化到本地文件后,有一天,这个对象的类发送了改变,我们用这个改变后的类接收序号化文件,会发生什么?把name和age注释掉,然后去反序列化。
public class User implements Serializable {//private String name; // //transient private int age; private Stringsex; private String phone; }public class Client {@Test public void write() throws Exception{ User user = new User(); //user.setAge(15); //user.setName("张三"); user.setPhone("123"); FileOutputStream fileOutputStream = new FileOutputStream("D://out.txt"); ObjectOutputStream objectOutputStream = new ObjectOutputStream(fileOutputStream); objectOutputStream.writeObject(user); }@Test public void read() throws Exception{ FileInputStream fileInputStream = new FileInputStream("D://out.txt"); ObjectInputStream objectInputStream = new ObjectInputStream(fileInputStream); User o = (User)objectInputStream.readObject(); System.out.println(o.toString()); }}

结果就是
java.io.InvalidClassException: com.example.service.demo01.User; local class incompatible: stream classdesc serialVersionUID = -118799779803260725, local class serialVersionUID = 1681826866445576943
这个报错是什么意思?是这个类和序列化文件里的类的序列号不一样,无法反序列化。
这里出现了一个问题,什么是序列号?
序列号是一个长整型的数据,一个类的序列号,是根据这个类的成员变量计算出来,如果成员变量发生改变,序列号也会发生改变,只有序列化文件的序列号和类的序列号相同,才能反序列化成功。
所以这个报错就很容易理解了,在改动前,类有三个变量,序列号的值假设是3,序列化的文件也是3,删除一个变量后,只剩两个变量,假设序列号是2,这样和序列化文件的序列号就不一样了,所以无法反序列化。
【Java|Java序列化和反序化】有时候,我们希望,即使类发生了改变,也能反序列化成功,比如之前有现在只剩3个字段,序列化的文件有4个字段,我们只序列化现在的类有的字段,那该怎么做?
我们可以手动为一个类设置序列号,像这样:
Java|Java序列化和反序化
文章图片

这样,即使类发生了改变,但是序列号我们已经手动写死了,之后类再怎么发生变化,反序列化也不会报错,只会序列话那些还能对应上的值。

    推荐阅读