serialVersionUID的用途是什么

原文: https://javabeginnerstutorial.com/core-java-tutorial/use-serialversionuid/

在这里,我将讨论在可序列化类中使用的变量serialVersionUID的重要性。

下面是一个使您了解变量的确切用法的示例。

示例代码

Employee.java

  1. package com.jbt;
  2. import java.io.Serializable;
  3. public class Employee implements Serializable
  4. {
  5. public String firstName;
  6. public String lastName;
  7. private static final long serialVersionUID = 5462223600l;
  8. }

SerializaitonClass.java(此类将用于序列化)

  1. package com.jbt;
  2. import java.io.FileOutputStream;
  3. import java.io.IOException;
  4. import java.io.ObjectOutputStream;
  5. public class SerializaitonClass {
  6. public static void main(String[] args) {
  7. Employee emp = new Employee();
  8. emp.firstName = "Vivekanand";
  9. emp.lastName = "Gautam";
  10. try {
  11. FileOutputStream fileOut = new FileOutputStream("./employee.txt");
  12. ObjectOutputStream out = new ObjectOutputStream(fileOut);
  13. out.writeObject(emp);
  14. out.close();
  15. fileOut.close();
  16. System.out.printf("Serialized data is saved in ./employee.txt file");
  17. } catch (IOException i) {
  18. i.printStackTrace();
  19. }
  20. }
  21. }

DeserializationClass.java(此类将用于反序列化)

  1. package com.jbt;
  2. import java.io.*;
  3. public class DeserializationClass {
  4. public static void main(String[] args) {
  5. Employee emp = null;
  6. try {
  7. FileInputStream fileIn = new FileInputStream("./employee.txt");
  8. ObjectInputStream in = new ObjectInputStream(fileIn);
  9. emp = (Employee) in.readObject();
  10. in.close();
  11. fileIn.close();
  12. } catch (IOException i) {
  13. i.printStackTrace();
  14. return;
  15. } catch (ClassNotFoundException c) {
  16. System.out.println("Employee class not found");
  17. c.printStackTrace();
  18. return;
  19. }
  20. System.out.println("Deserializing Employee...");
  21. System.out.println("First Name of Employee: " + emp.firstName);
  22. System.out.println("Last Name of Employee: " + emp.lastName);
  23. }
  24. }

现在执行“SerializationClass.java”,然后执行“DeserializationClass.java”。 它将首先创建一个具有Employee对象状态的文件,然后在反序列化时从同一文件创建一个对象。 输出将如下所示。

  1. Serialized data is saved in ./employee.txt file
  1. Deserializing Employee...
  2. First Name of Employee: Vivekanand
  3. Last Name of Employee: Gautam

现在让我们尝试从Employee.java文件中删除“serialVersionUID”变量,然后再次运行“SerializationClass.java”文件。 它将再次创建带有对象状态的“employee.txt”文件。 现在让我们在Employee类中假设字符串地址中添加一个新变量。

Employee.java

  1. package com.jbt;
  2. import java.io.Serializable;
  3. public class Employee implements Serializable
  4. {
  5. public String firstName;
  6. public String lastName;
  7. public String Address;
  8. //Variable is commented
  9. // private static final long serialVersionUID = 5462223600l;
  10. }

现在运行“DeserializationClass.java”并查看输出。

  1. java.io.InvalidClassException: com.jbt.Employee; local class incompatible: stream classdesc serialVersionUID = 5462223600, local class serialVersionUID = -3607530122250644586
  2. at java.io.ObjectStreamClass.initNonProxy(Unknown Source)
  3. at java.io.ObjectInputStream.readNonProxyDesc(Unknown Source)
  4. at java.io.ObjectInputStream.readClassDesc(Unknown Source)
  5. at java.io.ObjectInputStream.readOrdinaryObject(Unknown Source)
  6. at java.io.ObjectInputStream.readObject0(Unknown Source)
  7. at java.io.ObjectInputStream.readObject(Unknown Source)
  8. at com.jbt.DeserializationClass.main(DeserializationClass.java:11)

它将引发不兼容的异常。 因为给定的类Employee.java在序列化和反序列化过程之间进行了更改。 因此,系统无法识别它仍然是同一类。 为了使我们的系统了解到它是同一类,您必须在一个类中使用serialVersionUID变量。

您可以尝试执行上述步骤,但保持serialVersionUID不变,并查看输出。 反序列化过程将正常进行。

项目要点

  • 在可序列化类中定义serialVersionUID字段不是必需的。
  • 如果可序列化的类具有显式的serialVersionUID,则此字段的类型应为long,并且必须是静态且最终的。
  • 如果没有明确定义的serialVersionUID字段,则序列化运行时将计算该类的默认值。 该值可以根据编译器的实现而变化。 因此,建议定义serialVersionUID
  • 建议对serialVersionUID使用私有访问修饰符。
  • 不同的类可以具有相同的serialVersionUID
  • 数组类无法声明显式的serialVersionUID,因此它们始终具有默认的计算值,但是对于数组类,无需匹配serialVersionUID值。
  • 如果已加载的接收器类的serialVersionUID与相应的发送器类之间存在差异,则将引发InvalidClassException
  • 如果要禁止序列化同一类旧版本的新类,则应对同一类的不同版本使用不同的serialVersionUID

@SuppressWarnings(“serial”)

如果您没有在应该序列化的类中提供serialVersionId,则编译器将给出有关该序列的警告消息。 如果要覆盖此警告,则可以使用给定的注解。 使用后,编译器将不再报错缺少的serialVersionUID