Java序列化和反序列化

什么叫序列化和反序列化?

序列化:对象转化为字节序列的过程叫做对象的序列化

反序列化:字节序列恢复为对象的过程叫做对象的反序列化

为啥要序列化?(序列化的用途)

-需要将对象永久的保存在硬盘中(比如Session对象)

-网络传输对象的序列(网络中的二进制序列)

过程:

序列化的过程:创建一个对象输出流对象,调用对象的writeObject()函数

反序列化的过程,创建一个对象输入流,调用readObject()函数

例子:

package Note;

import java.io.*;

/**
 * @author yintianhao
 * @createTime 20190218 21:46
 * @description 序列化
 */
public class People implements Serializable {
    //序列化id
    private static final long serialVersionUID = -5809782578272943999L;

    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;
    }

    public static void main(String[] args) throws IOException,ClassNotFoundException {
        //序列化
        People one = new People();
        one.setAge(5);
        one.setName("张三");
        ObjectOutputStream stream = new ObjectOutputStream(new FileOutputStream(new File("G:/test.txt")));
        stream.writeObject(one);
        stream.close();

        //反序列化
        ObjectInputStream stream1 = new ObjectInputStream(new FileInputStream(new File("G:/test.txt")));
        People two = (People) stream1.readObject();
        System.out.println("Name = "+two.getName()+"--age = "+two.getAge());
        stream1.close();
    }
}
Code

检验一下G盘是否有这个test.txt

 再看Console

那么问题来了:serialVersionUID是干啥的? 

看字面上的意思就是版本号嘛,那么这个版本号是干啥的呢

那么就有必要了解一下序列化的过程了:

序列化操作的时候系统会把当前类的serialVersionUID写入到序列化文件中,当反序列化时系统会去检测文件中的serialVersionUID,判断它是否与当前类的serialVersionUID一致,如果一致就说明序列化类的版本与当前类版本是一样的,可以反序列化成功,否则失败。

当然这里是我自己指定的serialVersionUID,如果这里我们不写也是没问题的,因为如果我们自己没定义serialVersionUID

jdk会自行给我们生成一个serialVersionUID,但是一般情况IDE会报个警告,不知道为啥IDEA没报,但是Eclipse是报了...

第一句是生成默认的版本ID,值为

第二句是根据类的类名信息等生成的,值为

但是如果我们不指定ID,那么,如果我们修改了类中的信息,比如增加或者删除某个属性,那么我们在反序列化之前的

对象的时候就会报错,因为这个修改后的类的serialVersionUID已经变了,所以不能反序列化第一次的对象

打个比方增加一个性别sex的选项,然后为了验证把之前的序列化的过程去掉,看改完后的这个能不能反序列化之前的

代码如下:

package Note;

import java.io.*;

/**
 * @author yintianhao
 * @createTime 20190218 21:46
 * @description 序列化
 */
public class People implements Serializable {
    //序列化id

    private int age;
    private String name;
    private String sex;

    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;
    }

    public static void main(String[] args) throws IOException,ClassNotFoundException {
       

        //反序列化
        ObjectInputStream stream1 = new ObjectInputStream(new FileInputStream(new File("G:/test.txt")));
        People two = (People) stream1.readObject();
        System.out.println("Name = "+two.getName()+"--age = "+two.getAge());
        stream1.close();
    }
}
Code

运行,就报错了

Exception in thread "main" java.io.InvalidClassException: Note.People; local class incompatible: stream classdesc serialVersionUID = 8716394284034362776, local class serialVersionUID = 5389077117487999490
at java.io.ObjectStreamClass.initNonProxy(ObjectStreamClass.java:699)
at java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.java:1885)
at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1751)
at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:2042)
at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1573)
at java.io.ObjectInputStream.readObject(ObjectInputStream.java:431)
at Note.People.main(People.java:37)

这里这个ID是由JDK的生成的,根据类的一些细节信息生成,具体怎么生成的我们不管,但是像刚才那样我们是不愿看见的,因为不同的Java编译器可能生成的

ID就不一样,所以还是强烈建议自定义一个明确的serialVersionUID

参考博客:https://www.cnblogs.com/xdp-gacl/p/3777987.html

https://www.cnblogs.com/duanxz/p/3511695.html

原文地址:https://www.cnblogs.com/Yintianhao/p/10398455.html