一尘不染

什么是serialVersionUID,为什么要使用它?

java serialVersionUID

serialVersionUID缺少a时,Eclipse发出警告。

The serializable class Foo does not declare a static final serialVersionUID field of type long

阅读 838

收藏
2020-01-10

共2个答案

一尘不染

java.io.Serializable 你可能会得到的有关文档的解释很好:

序列化运行时与每个可序列化的类关联一个版本号,称为serialVersionUID,在反序列化过程中使用该版本号来验证序列化对象的发送者和接收者是否已加载了该对象的与序列化兼容的类。如果接收者为对象加载的类serialVersionUID与相应的发送者的类不同,则反序列化将导致 InvalidClassException。可序列化的类可以serialVersionUID通过声明一个serialVersionUID必须为staticfinaltype 的字段来显式声明其自身long

ANY-ACCESS-MODIFIER static final long serialVersionUID = 42L;

如果可序列化的类没有显式声明 serialVersionUID,则序列化运行时将根据serialVersionUID该类的各个方面为该类计算一个默认值,如Java对象序列化规范中所述。但是,强烈建议所有可序列化的类显式声明serialVersionUID值,因为默认serialVersionUID计算对类详细信息高度敏感,而类详细信息可能会根据编译器的实现而有所不同,因此可能导致InvalidClassExceptions反序列化期间发生意外情况。因此,为了保证serialVersionUID不同Java编译器实现之间的值一致,可序列化的类必须声明一个显式serialVersionUID值。还强烈建议明确serialVersionUID声明尽可能使用private修饰符,因为此类声明仅适用于立即声明的类serialVersionUID字段,不能用作继承成员。

2020-01-10
一尘不染

首先,我需要解释什么是序列化。

序列化 允许将对象转换为流,以便通过网络发送该对象,或者保存到文件或保存到DB以供使用。

有一些序列化规则。

  • 仅当对象的类或其超类实现Serializable接口时,该对象才可序列化
  • 一个对象是可序列化的(本身实现了Serializable接口),即使其超类不是。但是,可序列化类的层次结构中的第一个超类(不实现Serializable接口)必须具有无参数构造函数。如果违反此规定,则readObject()将在运行时生成java.io.InvalidClassException
  • 所有原始类型都是可序列化的。
  • 暂态字段(带有暂态修饰符)未序列化(即,未保存或恢复)。实现Serializable的类必须标记不支持序列化的类(例如文件流)的瞬态字段。
  • 静态字段(带有static修饰符)未序列化。

当Object被序列化,Java运行时关联的序列版本号又名的serialVersionID。

我们需要serialVersionID的位置: 在反序列化期间,验证发送者和接收者在序列化方面是否兼容。如果接收者给类加载了另一个类,serialVersionID反序列化将以结束InvalidClassCastException。
可序列化的类可以serialVersionUID通过声明一个serialVersionUID必须为静态,最终且类型为long的字段来显式声明其自身。

让我们尝试一个例子。

import java.io.Serializable;    
public class Employee implements Serializable {
private static final long serialVersionUID = 1L;
private String empname;
private byte empage;

public String getEmpName() {
    return name;
}
public void setEmpName(String empname) {
    this.empname = empname;
}
public byte getEmpAge() {
    return empage;
}
public void setEmpAge(byte empage) {
    this.empage = empage;
}

public String whoIsThis() {
    StringBuffer employee = new StringBuffer();
    employee.append(getEmpName()).append(" is ).append(getEmpAge()).append("
years old  "));
    return employee.toString();
}
}

创建序列化对象

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
public class Writer {
public static void main(String[] args) throws IOException {
    Employee employee = new Employee();
    employee.setEmpName("Jagdish");
    employee.setEmpAge((byte) 30);

    FileOutputStream fout = new
FileOutputStream("/users/Jagdish.vala/employee.obj");
    ObjectOutputStream oos = new ObjectOutputStream(fout);
    oos.writeObject(employee);
    oos.close();
    System.out.println("Process complete");
}
}

反序列化对象

import java.io.FileInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
public class Reader {
public static void main(String[] args) throws ClassNotFoundException,
IOException {
    Employee employee = new Employee();
    FileInputStream fin = new
    FileInputStream("/users/Jagdish.vala/employee.obj");
    ObjectInputStream ois = new ObjectInputStream(fin);
    employee = (Employee) ois.readObject();
    ois.close();
    System.out.println(employee.whoIsThis());
 }
}    

注意:现在更改Employee类的serialVersionUID并保存:

private static final long serialVersionUID = 4L;

并执行Reader类。不执行Writer类,你将获得异常。

Exception in thread "main" java.io.InvalidClassException:
com.jagdish.vala.java.serialVersion.Employee; local class incompatible:
stream classdesc serialVersionUID = 1, local class serialVersionUID = 4
at java.io.ObjectStreamClass.initNonProxy(ObjectStreamClass.java:616)
at java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.java:1623)
at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1518)
at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1774)
at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1351)
at java.io.ObjectInputStream.readObject(ObjectInputStream.java:371)
at com.krishantha.sample.java.serialVersion.Reader.main(Reader.java:14)
2020-01-10