它让我对Serializable
接口的启动感到困惑,为什么我必须在我的所有课程中加入这个字段。我知道这个接口需要一个唯一的标识符来标记类,但为什么它们不能在运行时生成它。例如,他们可以使用完全限定类名的MD5哈希或者用于处理罕见事件中的重复项的类似方法来生成它(也就是说,我确定,当被要求生成id时,eclipse会做什么)。
所以我要问的是(这篇文章不仅仅是针对标准库的咆哮)究竟是如何使用框架化序列化字段的呢?
我想知道的原因是因为我将尝试创建一个Aspect(在AspectJ或其他语言中),它将使用MD5哈希添加serialVersionUID字段,并且能够以可接受的方式处理冲突API。
如果能让它发挥作用,我会发布结果。
答案 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
包中。这是为了保护较小的更改而实现的,并且实现为使用户在运行时能够write
和save
对象。此接口由所有swing组件实现,因为开发人员可以扩展它们,以便JVM可以找到组件的新版本,即Your class
。
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的旧已经序列化的实例进行反序列化。