仅在方法更改时本地类不兼容的错误

时间:2015-04-16 03:04:06

标签: java backwards-compatibility serializable

我刚遇到“WTF”的错误:我更新了我的一个classe的方法并添加了一个方法。在运行我的程序之后,当程序试图打开并反序列化最近保存的数据时(在方法更改之前),这就是弹出的内容:

java.io.InvalidClassException: cz.autoclient.settings.Settings; local class incompatible: stream classdesc serialVersionUID = 2404650814140543454, local class serialVersionUID = 4256355437298300223

根据java文档所说的,java方法没有被序列化。那么为什么serialVersionUID也考虑了类方法?

由于Java程序员似乎对在任何地方使用getter和setter感到非常生气,为什么不能为serialVersionUID创建getter以便我可以实现自己只计算属性的算法?

serialVersionUID can be overriden,但只有static final long serialVersionUID值才会让我记得在更改类的属性时更改它。

2 个答案:

答案 0 :(得分:3)

基于java的文档,他们建议尽可能使用自定义serialVersionUID,因为默认算法将采用类实现细节,结果据说从JVM实现到另一个不同。

Java用于生成serialVersionUID的{​​{3}}似乎也在考虑非私有方法(步骤7)。如果您在实现中使用默认的serialVersionUID,则会解释该异常。

编辑: 正如您所建议的那样,如果我们可以使用自己的方法实现来执行此操作,而不是将serialVersionUID覆盖为static final long,那将会很棒。但我想他们不允许这样做,因为如果允许这样做,这种方法的错误实现可能会使serialVersionUID的整个目的失效。

答案 1 :(得分:1)

Oracle docs表示如果你不提供serialVersionUID,编译器会为你生成一个。

  

如果可序列化类没有显式声明serialVersionUID,则序列化运行时将根据类的各个方面计算该类的默认serialVersionUID值,如Java(TM)对象序列化规范中所述。 但是,强烈建议所有可序列化类显式声明serialVersionUID值,因为默认的serialVersionUID计算对类详细信息高度敏感,可能因编译器实现而异,因此在反序列化期间可能导致意外的InvalidClassExceptions 。因此,为了保证跨不同java编译器实现的一致的serialVersionUID值,可序列化类必须声明显式的serialVersionUID值。强烈建议显式serialVersionUID声明尽可能使用private修饰符,因为此类声明仅适用于立即声明的类 - serialVersionUID字段作为继承成员无用。数组类不能声明显式的serialVersionUID,因此它们总是具有默认的计算值,但是对于数组类,不需要匹配serialVersionUID值。

根据Java Object Serialization Specification section 5.1

  

版本控制引发了一些关于类的身份的基本问题,包括什么构成了兼容的变化。 兼容更改是一项不会影响班级与其来电者之间合同的更改。

这里发生的是编译器已经确定代码的两个版本之间的差异保证了新的serialVersionUID。如果您认为Object(1)和Object(2)的实例中包含的状态是可互换的,则应通过手动设置serialVersionUID并在这些更改之间保持相同来管理此状态。

是的,您必须手动管理它,并在更改管理类的内部状态的机制时更改它。

但请注意,如果公共方法发生了变化,您应该考虑该类的原始版本是否满足与新版本相同的期望。如果您希望将先前序列化状态中包含的数据加载到该类的新版本中,可能使用静态构造函数方法来初始化具有兼容旧状态的新版本(新行为)。