专注于 JetBrains IDEA 全家桶,永久激活,教程
持续更新 PyCharm,IDEA,WebStorm,PhpStorm,DataGrip,RubyMine,CLion,AppCode 永久激活教程

序列化与反序列化

序列化与反序列化是开发过程中不可或缺的一步,简单来说,序列化是将对象转换成字节流的过程,而反序列化的是将字节流恢复成对象的过程。两者的关系如下:

122_1.png

使用场景

1、 对象的持久化(将对象内容保存到数据库或文件中)
2、 远程数据传输(将对象发送给其他计算机系统)

为什么需要序列化与序列化?

序列化与序列化主要解决的是数据的一致性问题。简单来说,就是输入数据与输出数据是一样的。

对于数据的本地持久化,只需要将数据转换为字符串进行保存即可是实现,但对于远程的数据传输,由于操作系统,硬件等差异,会出现内存大小端,内存对齐等问题,导致接收端无法正确解析数据,为了解决这种问题,Sun Microsystems在20世纪80年代提出了XDR规范,于1995年正式成为IETF标准。

Java中的序列化与反序列化

Java语言内置了序列化和反序列化,通过Serializable接口实现。

public class Account implements Serializable {

    private int age;
    private long birthday;
    private String name;
}

序列化兼容性

序列化的兼容性指的是对象的结构变化(如增删字段,修改字段,字段修饰符的改变等)对序列化的影响。为了能够识别对象结构的变化,Serializable使用serialVersionUID字段来标识对象的结构。默认情况下,它会根据对象的数据结构自动生成,结构发生变化后,它的值也会跟随变化。虚拟机在反序列化的时候会检查serialVersionUID的值,如果字节码中的serialVersionUID和要被转换的类型的serialVersionUID不一致,就无法进行正常的反序列化。

示例:将Account对象保存到文件中,然后在Account类中添加address字段,再从文件中读取之前保存的内容。

// 将Account对象保存到文件中
FileOutputStream fos = new FileOutputStream(file);
ObjectOutputStream oos = new ObjectOutputStream(fos);
oos.writeObject(account);
oos.flush();

// 修改Account对象的结构
public class Account implements Serializable {

    private int age;
    private long birthday;
    private String name;
    private String address;

    public Account(int age, String name) {
        this.age = age;
        this.name = name;
    }
}   

// 读取Account的内容
FileInputStream fis = new FileInputStream(file);
ObjectInputStream ois = new ObjectInputStream(fis);
Account account2 = (Account)ois.readObject();

由于在保存Account对象后修改了Account的结构,会导致serialVersionUID的值发生变化,在读文件(反序列化)的时候就会出错。所以为了更好的兼容性,在序列化的时候,最好将serialVersionUID的值设置为固定的。

public class Account implements Serializable {

    private static final long serialVersionUID = 1L;

    private int age;
    private long birthday;
    private String name;
}

序列化的存储规则

Java中的序列化在将对象持久化(序列化)的时候,为了节省磁盘空间,对于相同的对象会进行优化。当多次保存相同的对象时,其实保存的只是第一个对象的引用。

// 将account对象保存两次,第二次保存时修改其用户名
Account account = new Account("Freeman");
FileOutputStream fos = new FileOutputStream(file);
ObjectOutputStream oos = new ObjectOutputStream(fos);
oos.writeObject(account);
System.out.println("fileSize=" +file.length());
account.setUserName("Tom");
oos.writeObject(account);
System.out.println("fileSize=" +file.length());

// 读取两次保存的account对象
FileInputStream fis = new FileInputStream(file);
ObjectInputStream ois = new ObjectInputStream(fis);
Account account2 = (Account)ois.readObject();
Account account3 = (Account)ois.readObject();
System.out.println("account2.name=" + account2.getUserName() + "\n  account3.name=" + account3.getUserName() + "\naccount2==account3 -> " + account2.equals(account3));

输出结果:

account2.name=Freeman  
account3.name=Freeman 
account2==account3 -> true

所以在对同一个对象进行多次序列化的时候,最好通过clone一个新的对象再进行序列化。

摘自

tech.souyunku.com5c47c8…

文章永久链接:https://tech.souyunku.com/27888

未经允许不得转载:搜云库技术团队 » 序列化与反序列化

JetBrains 全家桶,激活、破解、教程

提供 JetBrains 全家桶激活码、注册码、破解补丁下载及详细激活教程,支持 IntelliJ IDEA、PyCharm、WebStorm 等工具的永久激活。无论是破解教程,还是最新激活码,均可免费获得,帮助开发者解决常见激活问题,确保轻松破解并快速使用 JetBrains 软件。获取免费的破解补丁和激活码,快速解决激活难题,全面覆盖 2024/2025 版本!

联系我们联系我们