serialVersionUID的用途是什么
原文: https://javabeginnerstutorial.com/core-java-tutorial/use-serialversionuid/
在这里,我将讨论在可序列化类中使用的变量serialVersionUID
的重要性。
下面是一个使您了解变量的确切用法的示例。
示例代码
Employee.java
package com.jbt;
import java.io.Serializable;
public class Employee implements Serializable
{
public String firstName;
public String lastName;
private static final long serialVersionUID = 5462223600l;
}
SerializaitonClass.java
(此类将用于序列化)
package com.jbt;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
public class SerializaitonClass {
public static void main(String[] args) {
Employee emp = new Employee();
emp.firstName = "Vivekanand";
emp.lastName = "Gautam";
try {
FileOutputStream fileOut = new FileOutputStream("./employee.txt");
ObjectOutputStream out = new ObjectOutputStream(fileOut);
out.writeObject(emp);
out.close();
fileOut.close();
System.out.printf("Serialized data is saved in ./employee.txt file");
} catch (IOException i) {
i.printStackTrace();
}
}
}
DeserializationClass.java
(此类将用于反序列化)
package com.jbt;
import java.io.*;
public class DeserializationClass {
public static void main(String[] args) {
Employee emp = null;
try {
FileInputStream fileIn = new FileInputStream("./employee.txt");
ObjectInputStream in = new ObjectInputStream(fileIn);
emp = (Employee) in.readObject();
in.close();
fileIn.close();
} catch (IOException i) {
i.printStackTrace();
return;
} catch (ClassNotFoundException c) {
System.out.println("Employee class not found");
c.printStackTrace();
return;
}
System.out.println("Deserializing Employee...");
System.out.println("First Name of Employee: " + emp.firstName);
System.out.println("Last Name of Employee: " + emp.lastName);
}
}
现在执行“SerializationClass.java
”,然后执行“DeserializationClass.java
”。 它将首先创建一个具有Employee
对象状态的文件,然后在反序列化时从同一文件创建一个对象。 输出将如下所示。
Serialized data is saved in ./employee.txt file
Deserializing Employee...
First Name of Employee: Vivekanand
Last Name of Employee: Gautam
现在让我们尝试从Employee.java
文件中删除“serialVersionUID
”变量,然后再次运行“SerializationClass.java
”文件。 它将再次创建带有对象状态的“employee.txt
”文件。 现在让我们在Employee
类中假设字符串地址中添加一个新变量。
Employee.java
package com.jbt;
import java.io.Serializable;
public class Employee implements Serializable
{
public String firstName;
public String lastName;
public String Address;
//Variable is commented
// private static final long serialVersionUID = 5462223600l;
}
现在运行“DeserializationClass.java
”并查看输出。
java.io.InvalidClassException: com.jbt.Employee; local class incompatible: stream classdesc serialVersionUID = 5462223600, local class serialVersionUID = -3607530122250644586
at java.io.ObjectStreamClass.initNonProxy(Unknown Source)
at java.io.ObjectInputStream.readNonProxyDesc(Unknown Source)
at java.io.ObjectInputStream.readClassDesc(Unknown Source)
at java.io.ObjectInputStream.readOrdinaryObject(Unknown Source)
at java.io.ObjectInputStream.readObject0(Unknown Source)
at java.io.ObjectInputStream.readObject(Unknown Source)
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
。