什么是序列化反序列化?

  • Java序列化是将对象转换为字节流的过程,因此我们可以将其存储在磁盘上或通过网络发送。
  • 反序列化是相反的过程–将字节流转换为内存中的对象。

序列化过程

  • 在序列化期间,java运行时将版本号与每个可序列化的类相关联,此数字称为 serialVersionUID。
  • 在反序列化期间,用于验证序列化对象的发送者和接收者是否已为该对象加载了与序列化兼容的类。如果接收者为对象加载的类serialVersionUID与相应的发送者的类不同,则反序列化将导致InvalidClassException。

假设一个英国人和另一个印度人都将分别执行序列化和反序列化。在这种情况下, 为了验证在印度的接收者是经过验证的人,JVM会创建一个唯一ID,称为SerialVersionUID。

  • 在大多数情况下,序列化和反序列化这两个活动都是由具有相同系统和相同位置的单个人完成的。
  • 但是在序列化中,发送者和接收者不是同一个人,即,这些人可能不同,机器或系统可能不同,并且位置必须不同。在序列化中,发送方和接收方都应仅在开始时具有.class文件,即,要进行序列化的人和准备反序列化的人仅应在开始时包含相同的.class文件。
  • 序列化:序列化时,每个对象发送方JVM都会保存一个Unique Identifier。JVM负责根据发送方系统中存在的相应.class文件生成该唯一ID。
  • 反序列化:反序列化时,接收方JVM将与对象关联的唯一ID与本地类Unique ID进行比较,即JVM还将基于接收方系统中存在的相应.class文件创建唯一ID。如果两个唯一的ID都匹配,则将仅执行反序列化。否则,我们将获得Runtime Exception,提示InvalidClassException。这个唯一的标识符不过是SerialVersionUID。

SerialVersionUID的生成:

  • 就平台和版本而言,发送者和接收者都应使用相同的JVM。否则,由于不同的SerialVersionUID,接收器无法反序列化。
  • 发送方和接收方都应使用相同的.class文件版本。序列化后,如果接收方的.class文件中有任何更改,则接收方无法反序列化。
  • 为了在内部生成SerialVersionUID,JVM可能使用复杂的算法,这可能会导致性能问题。

示例

  • 可序列化的类可以通过声明一个名为“ serialVersionUID” 的字段来显式地声明其自己的serialVersionUID,该字段必须是静态的,且类型为long。
  • 在这里,serialVersionUID表示类的版本,如果您对类的当前版本进行了修改,以使其不再与先前的版本向后兼容,则应该对它进行递增。
  • 因为若不显式定义 serialVersionUID 的值,Java 会根据类细节自动生成 serialVersionUID 的值,如果对类的源代码作了修改,再重新编译,新生成的类文件的serialVersionUID的取值有可能也会发生变化。类的serialVersionUID的默认值完全依赖于Java编译器的实现,对于同一个类,用不同的Java编译器编译,也有可能会导致不同的serialVersionUID,而这会导致问题
//必须实现Serializable接口,不然抛出NotSerializableException
public class DataClass implements Serializable {
        // 自定义 SerialVersionUID,可序列化后修改,测试反序列化
        private static final long serialVersionUID = 20000L;
        String name = "sun";
        int age = 21;
}
public class Receiver {
        public static void main(String[] args) throws Exception {
            // 从 test.txt反序列化
            FileInputStream fis = new FileInputStream("test.txt");
            ObjectInputStream ois = new ObjectInputStream(fis);
            DataClass g = (DataClass)ois.readObject();
            System.out.println(g.age);
        }
}
public class Sender {
    public static void main(String[] args) throws IOException {
        DataClass g = new DataClass();
        // 序列化到该文件,实际可能是序列化到远程服务器
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("test.txt"));
        oos.writeObject(g);
        oos.close();
        System.out.println("全路径:"+System.getProperty("user.dir")+"test.txt");
    }
}

本博客仅供本人学习、记录,如有错误,恳请指出。