序列化和反序列化的概念及应用

Posted cj_eryue

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了序列化和反序列化的概念及应用相关的知识,希望对你有一定的参考价值。

1、序列化和反序列化的概念

  • 序列化:把对象转换为字节序列的过程。
  • 反序列化:把字节序列恢复为对象的过程称。

2、什么情况下需要序列化

  • 把内存中的对象状态保存到一个文件中或者数据库中时候;
  • 用套接字在网络上传送对象的时候;
  • 通过RMI传输对象的时候;

3、如何实现序列化

实现Serializable接口即可

package com.cjian.ser;

import java.io.Serializable;

/**
 * @Author: cjian
 * @Date: 2022/2/23 14:20
 * @Des:
 */
public class FlyPig implements Serializable 
    //static final long serialVersionUID = 1L;

    private static String AGE = "26";
    private String name;
    private String color;
    transient private String car;

    //private String addTip;

    public String getName() 
        return name;
    

    public void setName(String name) 
        this.name = name;
    

    public String getColor() 
        return color;
    

    public void setColor(String color) 
        this.color = color;
    

    public String getCar() 
        return car;
    

    public void setCar(String car) 
        this.car = car;
    

   /* public String getAddTip() 
        return addTip;
    

    public void setAddTip(String addTip) 
        this.addTip = addTip;
    */

    @Override
    public String toString() 
        return "FlyPig" +
                "name='" + name + '\\'' +
                ", color='" + color + '\\'' +
                ", car='" + car + '\\'' +
                //", addTip='" + addTip + '\\'' +
                '';
    

测试:

package com.cjian.ser;

import java.io.*;

/**
 * @Author: cjian
 * @Date: 2022/2/23 14:22
 * @Des:
 */
public class SerializableTest 
    /**
     * 序列化
     */
    private static void serializeFlyPig() throws IOException 
        FlyPig flyPig = new FlyPig();
        flyPig.setColor("black");
        flyPig.setName("naruto");
        flyPig.setCar("oooo");
        // ObjectOutputStream 对象输出流,将 flyPig 对象存储到G盘的 flyPig.txt 文件中,完成对 flyPig 对象的序列化操作
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(new File("G:/flyPig.txt")));
        oos.writeObject(flyPig);
        System.out.println("FlyPig 对象序列化成功!");
        oos.close();
    

    /**
     * 反序列化
     */
    private static FlyPig deserializeFlyPig() throws Exception 
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream(new File("G:/flyPig.txt")));
        FlyPig person = (FlyPig) ois.readObject();
        System.out.println("FlyPig 对象反序列化成功!");
        return person;
    

    public static void main(String[] args) throws Exception 
        serializeFlyPig();
        FlyPig flyPig = deserializeFlyPig();
        System.out.println(flyPig.toString());

    

 

从运行结果上看:
1、实现了对象的序列化和反序列化。
2、transient 修饰的属性,是不会被序列化的。我设置的ca不见啦,成了null。
3、这个静态变量AGE也被序列化啦。真的被序列化了吗?  接下来验证下

修改main方法,先执行序列化:

修改AGE属性为 26,然后执行反序列化

 

 结果:

 可以看到,刚刚序列化时的269,没有反序列化出来,反序列化出来的而是刚刚修改的26,
所以,得出结论,这个静态static的属性,它不序列化。

4、serialVersionUID 的作用和用法

①我们先去掉serialVersionUID 接口,然后执行后面的序列化和反序列化的方法,

 

 

直接出异常:

 ②

还和上面的操作差不多,先是单独执行序列化方法。生成文件。
    然后,打开属性 addTip ,这之后,再次执行反序列化方法,看现象。

bean里面是没有明确的给这个 serialVersionUID 赋值,但是,Java会自动赋值的,这个值是根据这个bean的属性计算出来的。序列化的时候,还没有这个addTip属性,所以,自动生成的serialVersionUID 这个值和在我反序列化的时候Java自动生成的这个serialVersionUID值是不同的,就抛异常了(也可以反过来测,带ID去序列化,然后,没ID去反序列化。也是同样的问题)。
 

③再来一次,就是先序列化,这个时候,把 private static final long serialVersionUID = 1L; 这行代码的注释打开。那个addTip属性先注释掉,序列化之后,再把这个属性打开,再反序列化。看看什么情况。

 

这个现象的意义:

确保了一个bean在序列化与反序列化时的一个唯一性

所以,有这么个理论,就是在实现这个Serializable 接口的时候,一定要给这个 serialVersionUID 赋值

如何给 serialVersionUID 赋值呢?

使用编码工具自动生成的即可,如idea:

File -> Settings -> Editor -> Inspections -> 搜索 Serialization issues ,找到 Serializable class without 'serialVersionUID' ->打上勾,Apply->OK

 

自动生成的:

 

 5、其它:

        可序列化类的所有子类型本身都是可序列化的。因为实现接口也是间接的等同于继承。
序列化接口没有方法或字段,仅用于标识可序列化的语义。

        序列化运行时使用一个称为 serialVersionUID 的版本号与每个可序列化类相关联,该序列号在反序列化过程中用于验证序列化对象的发送者和接收者是否为该对象加载了与序列化兼容的类。如果接收者加载的该对象的类的 serialVersionUID 与对应的发送者的类的版本号不同,则反序列化将会导致 InvalidClassException。可序列化类可以通过声明名为 “serialVersionUID” 的字段(该字段必须是静态 (static)、最终 (final) 的 long 型字段)显式声明其自己的 serialVersionUID:

  如果可序列化类未显式声明 serialVersionUID,则序列化运行时将基于该类的各个方面计算该类的默认 serialVersionUID 值,如“Java™ 对象序列化规范”中所述。不过,强烈建议 所有可序列化类都显式声明 serialVersionUID 值,原因是计算默认的 serialVersionUID 对类的详细信息具有较高的敏感性,根据编译器实现的不同可能千差万别,这样在反序列化过程中可能会导致意外的 InvalidClassException。因此,为保证 serialVersionUID 值跨不同 java 编译器实现的一致性,序列化类必须声明一个明确的 serialVersionUID 值。还强烈建议使用 private 修饰符显示声明 serialVersionUID(如果可能),原因是这种声明仅应用于直接声明类 – serialVersionUID 字段作为继承成员没有用处。数组类不能声明一个明确的 serialVersionUID,因此它们总是具有默认的计算值,但是数组类没有匹配 serialVersionUID 值的要求。

以上是关于序列化和反序列化的概念及应用的主要内容,如果未能解决你的问题,请参考以下文章

广义表的概念及存储表示

24 Java学习之对象序列化和反序列化

Hash算法的概念及应用如何判断链表中是否有环

java序列化和反序列化

AutoCAD 凸度(bulge)的概念及使用WPF函数画图

无法反序列化当前的JSON对象,为啥