zoukankan      html  css  js  c++  java
  • java序列化和反序列化中的serialVersionUID有啥用

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

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

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

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

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

      假设现在有一个Student类,我们要对Student类进行序列化操作

      ①该类必须实现Serializable接口

    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方法中执行序列化和反序列化操作

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

      输出结果:张三

      即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有两种用途:
        1、 在某些场合,希望类的不同版本对序列化兼容,因此需要确保类的不同版本具有相同的serialVersionUID;
        2、 在某些场合,不希望类的不同版本对序列化兼容,因此需要确保类的不同版本具有不同的serialVersionUID。

  • 相关阅读:
    内核驱动系列中断和定时器
    apue2 阅读笔记第四章
    apue2 阅读笔记 第五章
    apue2阅读笔记 第6.7章
    再试试windows7版得writer
    内核驱动系列内核调试方法
    apue2 阅读笔记第三章
    杂谈关于代码库
    know everything about something
    React的父子传值(父传子)
  • 原文地址:https://www.cnblogs.com/zhangyongJava/p/10275416.html
Copyright © 2011-2022 走看看