java序列化和反序列化中的serialVersionUID有啥用

 1.什么是序列化和反序列化java

  序列化就是将java对象转成字节序列的过程;反序列化就是将字节序列转成java对象的过程。算法

   java中,序列化的目的一种是须要将对象保存到硬盘上,一种是对象须要在网络中传输json

2.序列化和反序列化的方式网络

  序列化和反序列化有不少种方式,如JDK类库中提供的序列化API、经常使用的json工具类等。本篇博客使用JDK提供的序列化API进行演示。重点说明serialVersionUID的做用。工具

  假设如今有一个Student类,咱们要对Student类进行序列化操做测试

  ①该类必须实现Serializable接口this

public class Student implements Serializable{

    private static final long serialVersionUID = -595470438262181967L;

    private String name ;
     
    private String sex;
    
    public String getName() {
        return name;
    }
 
    public void setName(String name) {
        this.name = name;
    }

    public String getSex() {
        return sex;
    }

    public void setSex(String sex) {
        this.sex = sex;
    }
    
}

  ②在main方法中执行序列化和反序列化操做spa

    public static void main(String[] args) throws Exception {
        
        //序列化
        OutputStream os = new FileOutputStream(new File("D://student.txt"));
        ObjectOutputStream oos = new ObjectOutputStream(os);
        Student student = new Student();
        student.setName("张三");
        student.setSex("男");
        oos.writeObject(student);
        
        //反序列化
        InputStream is = new FileInputStream(new File("D://student.txt"));
        ObjectInputStream ois = new ObjectInputStream(is);
        Student student1 = new Student();
        student1 = (Student) ois.readObject();
        System.out.println(student1.getName());
    }

  输出结果:张三code

  即student1对象在反序列化时进行了赋值对象

3.为何要serialVersionUID

  s​e​r​i​a​l​V​e​r​s​i​o​n​U​I​D​:​ ​字​面​意​思​上​是​序​列​化​的​版​本​号​,凡是实现Serializable接口的类都有一个表示序列化版本标识符的静态变量。

  (1)下面进行测试,若是没有s​e​r​i​a​l​V​e​r​s​i​o​n​U​I​D会出现什么?

    ①去掉Student类中的s​e​r​i​a​l​V​e​r​s​i​o​n​U​I​D属性。执行main方法,结果显示序列化成功!输出张三

    ②修改Student类,在Student类中添加number字段

public class Student implements Serializable{

    private String name ;
     
    private String sex;

    private String number;
    
    public String getName() {
        return name;
    }
 
    public void setName(String name) {
        this.name = name;
    }

    public String getSex() {
        return sex;
    }

    public void setSex(String sex) {
        this.sex = sex;
    }

    public String getNumber() {
        return number;
    }

    public void setNumber(String number) {
        this.number = number;
    }
    
}

  不执行序列化方法,只执行反序列化方法,结果出现异常:

Exception in thread "main" java.io.InvalidClassException: com.iot.study.serialize.Student; local class incompatible: stream classdesc serialVersionUID = -595470438262181967, local class serialVersionUID = -4254220179260112271
    at java.io.ObjectStreamClass.initNonProxy(ObjectStreamClass.java:621)
    at java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.java:1623)
    at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1518)
    at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1774)
    at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1351)
    at java.io.ObjectInputStream.readObject(ObjectInputStream.java:371)
    at com.iot.study.serialize.Client.main(Client.java:35)

  意思是原来序列化的时候(没有指定serialVersionUID)硬盘存的class的 serialVersionUID = -595470438262181967,而当前class的serialVersionUID = -4254220179260112271。 两者不同,没法反序列化。

  缘由分析:

    serialVersionUID没有指定时,java编译器会自动给这个class进行一个摘要算法,相似于指纹算法,只要这个文件 多一个空格,获得的UID就会大相径庭的,能够保证在这么多类中,这个编号是惟一的。因此,添加了一个number字段后,因为没有显指定 serialVersionUID,编译器又为咱们生成了一个UID,固然和前面保存在文件中的那个不会同样了,因而就出现了2个序列化版本号不一致的错误。

  (2)指定serialVersionUID测试

  若是为Student类显示的指定serialVersionUID,那么在序列化和反序列化的时候,即便修改了Student类中的部份内容,也能序列化成功。

4.serialVersionUID的取值

  serialVersionUID的取值是Java运行时环境根据类的内部细节自动生成的。若是对类的源代码做了修改,再从新编译,新生成的类文件的serialVersionUID的取值有可能也会发生变化。
  类的serialVersionUID的默认值彻底依赖于Java编译器的实现,对于同一个类,用不一样的Java编译器编译,有可能会致使不一样的 serialVersionUID,也有可能相同。为了提升serialVersionUID的独立性和肯定性,强烈建议在一个可序列化类中显示的定义serialVersionUID,为它赋予明确的值

  显式地定义serialVersionUID有两种用途:    一、 在某些场合,但愿类的不一样版本对序列化兼容,所以须要确保类的不一样版本具备相同的serialVersionUID;    二、 在某些场合,不但愿类的不一样版本对序列化兼容,所以须要确保类的不一样版本具备不一样的serialVersionUID。

相关文章
相关标签/搜索