当缺少serialVersionUID时,Eclipse会发出警告。

可序列化类Foo未声明静态finallong类型的serialVersionUID字段

什么是serialVersionUID,为什么它很重要?请显示缺少serialVersionUID将导致问题的示例。


当前回答

如果CheckStyle能够验证实现Serializable的类上的serialVersionUID是否具有良好的值,即它与串行版本id生成器将生成的值相匹配,这将是一件好事。例如,如果您有一个包含大量可序列化DTO的项目,那么记住删除现有的serialVersionUID并重新生成它是一件痛苦的事,而目前验证这一点的唯一方法(据我所知)是为每个类重新生成并与旧类进行比较。这是非常痛苦的。

其他回答

如果您在一个从未想过序列化的类上收到此警告,并且您没有声明自己实现了Serializable,这通常是因为您继承了一个实现Serializable的超类。通常情况下,最好委托给这样的对象,而不是使用继承。

所以

public class MyExample extends ArrayList<String> {

    public MyExample() {
        super();
    }
    ...
}

do

public class MyExample {
    private List<String> myList;

    public MyExample() {
         this.myList = new ArrayList<String>();
    }
    ...
}

并且在相关方法中调用myList.foo()而不是this.foo()(或super.foo(())

我经常看到有人在扩展JFrame之类的东西,而实际上他们只需要授权。(这也有助于在IDE中自动完成,因为JFrame有数百个方法,当您想在类中调用自定义方法时,不需要这些方法。)

警告(或serialVersionUID)不可避免的一种情况是,从AbstractAction(通常在匿名类中)扩展时,只添加actionPerformed方法。我认为在这种情况下不应该有警告(因为你通常无法可靠地序列化和反序列化这些匿名类,不管是在你的类的不同版本中),但我不确定编译器如何识别这一点。

SerialVersionUID用于对象的版本控制。也可以在类文件中指定serialVersionUID。不指定serialVersionUID的结果是,当您添加或修改类中的任何字段时,已经序列化的类将无法恢复,因为为新类和旧序列化对象生成的serialVersionID将不同。Java序列化过程依赖于正确的serialVersionUID来恢复序列化对象的状态,并在serialVersionID不匹配的情况下抛出Java.io.InvalidClassException

阅读更多信息:http://javarevisited.blogspot.com/2011/04/top-10-java-serialization-interview.html#ixzz3VQxnpOPZ

这个问题在Joshua Bloch的《有效Java》中有很好的记录。一本非常好的书,是一本必读的书。我将概述以下原因:

序列化运行时为每个可序列化类提供一个名为Serialversion的数字。此编号称为serialVersionUID。现在这个数字背后有一些数学,它是基于类中定义的字段/方法得出的。对于同一类,每次都会生成相同的版本。在反序列化过程中使用此数字来验证序列化对象的发送方和接收方是否已为该对象加载了与序列化兼容的类。如果接收方为对象加载的类具有与对应发送方类不同的serialVersionUID,则反序列化将导致InvalidClassException。

如果类是可序列化的,则还可以通过声明名为“serialVersionUID”的字段来显式声明自己的serialVersionUID,该字段必须是静态的、final的和long类型的。大多数IDE(如Eclipse)都可以帮助您生成长字符串。

为什么在Java中的Serializable类中使用SerialVersionUID?

在序列化期间,Java运行时为类创建一个版本号,以便以后可以对其进行反序列化。此版本号在Java中称为SerialVersionUID。

SerialVersionUID用于序列化数据的版本。只有当类的SerialVersionUID与序列化实例匹配时,才能对其进行反序列化。当我们不在类中声明SerialVersionUID时,Java运行时会为我们生成它,但不建议这样做。建议将SerialVersionUID声明为私有静态最终长变量,以避免默认机制。

当您通过实现标记接口java.io.Serializable将类声明为Serializable时,如果您没有使用Externalizable接口自定义进程,java运行时将该类的实例通过默认Serialization机制持久化到磁盘中。

另请参阅为什么在Java中的Serializable类中使用SerialVersionUID

最初的问题是问“为什么它很重要”和“示例”,这个串行版本ID在哪里有用。我找到了一个。

假设您创建了一个Car类,将其实例化,并将其写入对象流。扁平的汽车对象在文件系统中放置一段时间。同时,如果通过添加新字段来修改Car类。稍后,当您尝试读取(即反序列化)扁平化的Car对象时,会得到java.io.InvalidClassException——因为所有可序列化的类都会自动给定一个唯一的标识符。当类的标识符不等于展平对象的标识符时,将引发此异常。如果你真的想一想,由于添加了新字段,就会引发异常。通过声明显式的serialVersionUID来控制版本控制,可以避免引发此异常。显式声明serialVersionUID(因为不必计算)也有一个小的性能优势。因此,最好在创建Serializable类后立即将自己的serialVersionUID添加到它们中,如下所示:

public class Car {
    static final long serialVersionUID = 1L; //assign a long value
}