Serializable & serialVersionUID作用

序列化是一种对象持久化的手段,普遍应用在网络传输、RMI等场景中,类通过实现 java.io.Serializable 接口以启用其序列化功能。
但是,还有一个知识点并未展开介绍,那就是关于serialVersionUID ,这个字段到底有什么用?

一、Serializable

1.1 简介

Java类通过实现 java.io.Serializable 接口以启用其序列化功能。未实现此接口的类将无法进行序列化或反序列化。可序列化类的所有子类型本身都是可序列化的。

1.2 作用

在分布式应用中,就得实现序列化,如果不是分布式应用,就没必要实现序列化,因为:

  1. 将对象的状态保存在存储媒体中以便可以在以后重新创建出完全相同的副本
  2. 按值将对象从一个应用程序域发送至另一个应用程序域
    Serializable接口没有方法或字段,仅用于标识可序列化的语义。但是,如果一个类没有实现这个接口,想要被序列化的话,就会抛出java.io.NotSerializableException异常。

1.3 情景

  1. 当你想把内存中的对象写入到硬盘的时候
    内存不够用的时候,计算机就将内存里面的一部分对象暂存到硬盘,等到要用的时候再取出来,硬盘存储的空间就是虚拟内存
  2. 当你想用套接字在网络上传输对象的时候
    有时候传输某一类的对象,有时候就要实现Seriailzable接口,最常见的传输一个字符串,是JDK里面的类,也实现了Serializable接口,所以可以传输
  3. 当你想通过RMI传输对象的时候
    serialVersionUID适用于Java的序列化机制。简单来说,Java的序列化机制是通过判断类的serialVersionUID来验证版本一致性的。在进行反序列化时,JVM会把传来的字节流中的serialVersionUID与本地相应实体类的serialVersionUID进行比较,如果相同就认为是一致的,可以进行反序列化,否则就会出现序列化版本不一致的异常,即是InvalidCastException。

二、serialVersionUID

1.1 作用

序列化是将对象的状态信息转换为可存储或传输的形式的过程。我们都知道,Java对象是保存在JVM的堆内存中的,也就是说,如果JVM堆不存在了,那么对象也就跟着消失了。
而序列化提供了一种方案,可以让你在即使JVM停机的情况下也能把对象保存下来的方案。就像我们平时用的U盘一样。把Java对象序列化成可存储或传输的形式(如二进制流),比如保存在文件中。这样,当再次需要这个对象的时候,从文件中读取出二进制流,再从二进制流中反序列化出对象。
虚拟机是否允许反序列化,不仅取决于类路径和功能代码是否一致,一个非常重要的一点是两个类的序列化 ID 是否一致,这个所谓的序列化ID,就是我们在代码中定义的serialVersionUID。

1.2 如果serialVersionUID变了会怎样

假设有一个Team类,serialVersionUID的值为1L,我们将对象序列化,写入文件中。然后我们把文件中的对象反序列化出来,成功反序列化。
然后我们对Team类做修改,并将serialVersionUID的值改为2L,我们再将文件中的对象反序列化出来,反序列化失败,并抛出了一个java.io.InvalidClassException,并且指出serialVersionUID不一致。
这是因为,在进行反序列化时,JVM会把传来的字节流中的serialVersionUID与本地相应实体类的serialVersionUID进行比较,如果相同就认为是一致的,可以进行反序列化,否则就会出现序列化版本不一致的异常,即是InvalidCastException。
这也是《阿里巴巴Java开发手册》中规定,在兼容性升级中,在修改类的时候,不要修改serialVersionUID的原因。除非是完全不兼容的两个版本。所以,serialVersionUID其实是验证版本一致性的。

1.3 实现了Serializable接口,为什么要明确定义一个serialVersionUID

如果我们没有在类中明确的定义一个serialVersionUID的话,看看会发生什么。
假设有一个Team类,该类中不定义serialVersionUID,我们将对象序列化,写入文件中。然后我们把文件中的对象反序列化出来,成功反序列化。
然后我们对Team类做修改,向其中新增一个字段,我们再将文件中的对象反序列化出来,反序列化失败,并抛出了一个java.io.InvalidClassException,并且指出serialVersionUID不一致。
我们会发现,系统会自动添加一个serialVersionUID,导致两次serialVersionUID不一致。那系统的serialVersionUID是怎么生成的呢?在没有定义serialVersionUID的时候,会调用computeDefaultSUID 方法,生成一个默认的serialVersionUID。
所以,一旦类实现了Serializable,就建议明确的定义一个serialVersionUID。不然在修改类的时候,就会发生异常。

1.4 serialVersionUID生成方式

一种是默认的1L,比如:

private static final long serialVersionUID = 1L;

另外一种是根据类名、接口名、成员方法及属性等来生成一个64位的哈希字段,比如:
private static final long serialVersionUID = xxxxL;
后边这一种,可以通过IDE实现:
Serializable & serialVersionUID作用_第1张图片
然后回到实现Serializable的类中,可一键生成。
Serializable & serialVersionUID作用_第2张图片

你可能感兴趣的:(Java,java,开发语言)