为什么serialVersionUID字段存在?

时间:2012-09-07 01:08:14

标签: java serializable aspects serialversionuid

它让我对Serializable接口的启动感到困惑,为什么我必须在我的所有课程中加入这个字段。我知道这个接口需要一个唯一的标识符来标记类,但为什么它们不能在运行时生成它。例如,他们可以使用完全限定类名的MD5哈希或者用于处理罕见事件中的重复项的类似方法来生成它(也就是说,我确定,当被要求生成id时,eclipse会做什么)。

所以我要问的是(这篇文章不仅仅是针对标准库的咆哮)究竟是如何使用框架化序列化字段的呢?

我想知道的原因是因为我将尝试创建一个Aspect(在AspectJ或其他语言中),它将使用MD5哈希添加serialVersionUID字段,并且能够以可接受的方式处理冲突API。

如果能让它发挥作用,我会发布结果。

4 个答案:

答案 0 :(得分:9)

无需拥有serialVersionUID字段。如果您不提供,则Java将根据您的类的字段和方法生成一个。

您可能希望指定serialVersionUID的原因是为了防止在更改方法时更改值,这不会影响序列化二进制文件。考虑上课:

public class Person implements Serializable {
    private String name;
    public String getName() {
        return name;
    }
}

未指定serialVersionUID。如果您运行serialver Person,则会返回:

Person:    static final long serialVersionUID = 3793453319058452486L;

现在您决定添加一个方法,但保持字段相同。

public class Person implements Serializable {
    private String name;
    public String getName() {
        return name;
    }
    public Object foo() {
        return "bar";
    }
}

序列化二进制文件仍与旧版本完全兼容,但serialVersionUID不同:

Person:    static final long serialVersionUID = -6188734029437600310L;

使用不同的serialVersionUID,反序列化将导致serialVersionUID不匹配错误。解决方法是通过将其设置为任何值(我将其设置为serialVersionUID)并在字段更改时更改它来声明您自己的1L

另请参阅此related question "What is a serialVersionUID and why should I use it?"以获取更详细的讨论。

答案 1 :(得分:4)

  

为什么我必须在我的所有课程中加入这个字段

你没有。

  

为什么他们无法在运行时生成这个

他们这样做,除非你自己提供。

  

我将尝试创建一个Aspect(使用AspectJ或其他语言),它将使用MD5哈希添加serialVersionUID字段

那毫无意义。你不明白它的用途。在运行时生成它是默认情况下已经发生的情况,因此您的提案不会添加任何值。该值在编译时指定它,以便吸收实际上不会破坏对象版本兼容性的次要类更改。你无法通过AOP实现这一目标。这是一个编码决定。

答案 2 :(得分:0)

Serializable接口

此接口存在于java.io包中。这是为了保护较小的更改而实现的,并且实现为使用户在运行时能够writesave对象。此接口由所有swing组件实现,因为开发人员可以扩展它们,以便JVM可以找到组件的新版本,即Your class

的serialVersionUID

serialVersionUID用作Serializable类中的版本控件。如果您未基于Serializable类的各个方面明确声明serialVersionUID JVM will did it for you automatically,请参阅Java(TM) Object Serialization Specification

中的描述

答案 3 :(得分:0)

正如@Steve Kuo所提到的,不需要serialVersionUID字段。

令人沮丧的是,因为它没有被强制作为Object可以序列化的合同的一部分,我们团队中约有一半的开发人员这样做,而另一半则没有。通常只设置private static final long serialVersionUID = 1L;的大多数人(虽然有些开发人员喜欢把它作为一个机会尝试用伪随机的Longs ...)

有人说过,我一直都认为这是对Serializable对象进行版本化的初步尝试。

假设我们有:

public class PersonDTO implements Serializable {

    private static final long serialVersionUID = 1L;

    private String firstName;
    private String lastName;

    // Appropriate getters/setters of course
}

稍后我们要添加一个新字段private String middleInitial

如果我们将serialVersionUID提升为2,我们可以使用它来表明该类已经更改,并且使用此修改后的类定义无法使用serialVersionUID对PersonDTO的旧已经序列化的实例进行反序列化。