zoukankan      html  css  js  c++  java
  • 序列化和反序列化

    一、序列化和反序列化的定义

    1.序列化:把java对象转换为二进制字节序列的过程
    反序列化:把二进制字节恢复为对象的过程。

    2.序列化的主要用途

    • 把一个java对象通过序列化后永久的保存到硬盘上,例如通过文件保存在硬盘上
    • 在网络上通过流传送对象的字节序列

    二.序列化和反序列化使用

    在java中,只有实现了Serializable接口和Externalizable接口的类的对象才能被序列化,Externalizable接口继承自 Serializable接口,实现Externalizable接口的类完全由自身来控制序列化的行为,而仅实现Serializable接口的类可以 采用默认的序列化方式 对象序列化的过程如下:

     1 /**      
     2 *    序列化和反序列化
     3 */
     4 class Test implements Serializable{
     5 
     6     /**
     7      * 序列化ID
     8      */
     9     private static final long serialVersionUID = -2281553568822627366L;
    10     private String name;
    11     private int num;
    12     public static int num2 = 10; 
    13     public String getName() {
    14         return name;
    15     }
    16     public void setName(String name) {
    17         this.name = name;
    18     }
    19     public int getNum() {
    20         return num;
    21     }
    22     public void setNum(int num) {
    23         this.num = num;
    24     }
    25 }
    26 public class Demo{
    27     
    28     public static void main(String[] args) {
    29         //将对象序列化成字节并存放到文件中
    30         Test test = new Test();
    31         test.setName("aa");
    32         test.setNum(1);
    33         System.out.println("序列化前:"+test.num2);
    34         ObjectOutputStream oos=null;
    35         try {
    36             oos = new ObjectOutputStream(new FileOutputStream("E:\test\result.txt"));
    37             oos.writeObject(test);
    38             oos.close();
    39             //序列化后改变静态变量的值
    40             Test.num2 = 1000;
    41             ObjectInputStream ois = new ObjectInputStream(new FileInputStream("E:\test\result.txt"));
    42             Test test2 = (Test) ois.readObject();
    43             ois.close();
    44             
    45             System.out.println("反序列回来的对象的信息:");
    46             System.out.println("name:"+test2.getName());
    47             System.out.println("num:"+test2.getNum());
    48             System.out.println("num2:"+test.num2);
    49         } catch (FileNotFoundException e) {
    50             e.printStackTrace();
    51         } catch (IOException e) {
    52             e.printStackTrace();
    53         } catch (ClassNotFoundException e) {
    54             e.printStackTrace();
    55         }
    56     }
    57     
    58 }

    结果输出:

    结果输出:
    序列化前:10
    反序列回来的对象的信息:
    name:aa
    num:1
    num2:1000

    结果可知,序列化保存的是对象的状态,被序列化的对象的静态变量是属于类的状态,因此序列化并不保存静态变量。

    三、serialVersionUID的作用

    s​e​r​i​a​l​V​e​r​s​i​o​n​U​I​D​:​ ​字​面​意​思​上​是​序​列​化​的​版​本​号​,凡是实现Serializable接口的类都有一个表示序列化版本标识符的静态变量,实现Serializable接口的类如果类中没有添加serialVersionUID,一般,在开发工具中都会给预警,那么意味着这个字段肯定是有作用的。那么具体的作用是什么呢?其实,这个序列化ID起着关键的作用,它决定着是否能够成功反序列化!简单来说,java的序列化机制是通过在运行时判断类的serialVersionUID来验证版本一致性的。在进行反序列化时,JVM会把传来的字节流中的serialVersionUID与本地实体类中的serialVersionUID进行比较,如果相同则认为是一致的,便可以进行反序列化,否则就会报序列化版本不一致的异常。如修改上述代码:

    /**      
    *    序列化和反序列化
    */
    class Test implements Serializable{
    
        /**
         * 序列化ID
         */
        //private static final long serialVersionUID = -2281553568822627366L;
        private static final long serialVersionUID = -2281553568822627367L;//对对象序列化后,修改序列化版本ID
        private String name;
        private int num;
        public static int num2 = 10; 
        public String getName() {
            return name;
        }
        public void setName(String name) {
            this.name = name;
        }
        public int getNum() {
            return num;
        }
        public void setNum(int num) {
            this.num = num;
        }
    }
    public class Demo{
        
        public static void main(String[] args) {
            //将对象序列化成字节并存放到文件中
            /*Test test = new Test();
            test.setName("aa");
            test.setNum(1);
            ObjectOutputStream oos=null;*/
            try {
                /*oos = new ObjectOutputStream(new FileOutputStream("E:\test\result.txt"));
                oos.writeObject(test);
                oos.close();
                //序列化后改变静态变量的值
    */            Test.num2 = 1000;
                //修改序列化ID后,重新进行反序列化,此时本地Test类的序列化ID已经修改!
                ObjectInputStream ois = new ObjectInputStream(new FileInputStream("E:\test\result.txt"));
                Test test2 = (Test) ois.readObject();
                ois.close();
                
                System.out.println("反序列回来的对象的信息:");
                System.out.println("name:"+test2.getName());
                System.out.println("num:"+test2.getNum());
                System.out.println("num2:"+test2.num2);
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            }
        }
        
    }

    结果输出:

    java.io.InvalidClassException: com.demo.Test; local class incompatible: stream classdesc serialVersionUID = -2281553568822627366, local class serialVersionUID = -2281553568822627367
        at java.io.ObjectStreamClass.initNonProxy(ObjectStreamClass.java:687)
        at java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.java:1876)
        at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1745)
        at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:2033)
        at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1567)
        at java.io.ObjectInputStream.readObject(ObjectInputStream.java:427)
        at com.demo.Demo.main(Demo.java:60)

    结果表明,序列化ID的作用正如前面描述的那样, 虚拟机是否允许反序列化,不仅取决于类路径和功能代码是否一致,一个非常重要的一点是两个类的序列化 ID 是否一致(就是 private static final long serialVersionUID = 1L)。

  • 相关阅读:
    阿里P8推荐的SpingBoot学习手册+Git开源项目实践分享,还不收藏
    阿里P8划重点:JVM+Spring+Mybatis+多线程高并发源码你必须会
    一线大厂工程师推荐:Mysql、Springboot、JVM、Spring等面试合集
    GitHub标星120K+的JDK并发编程指南,连续霸榜GitHub终于开源了
    腾讯被指劝退高龄员工,华为百度也在优化,互联网35岁+该怎么办
    天猫面试官硬核推荐:Dubbo+ES+JVM+多线程/高并发+消息队列
    多线程与高并发:金九银十跳槽季面试必须要掌握的硬核涨薪技能
    纯干货,源码6步曲,带你解析完整的ThreadPoolExecutor
    今日总结
    今日头条技术架构分析
  • 原文地址:https://www.cnblogs.com/liupiao/p/9274146.html
Copyright © 2011-2022 走看看