Java 仅更改方法时出现本地类不兼容错误

Java 仅更改方法时出现本地类不兼容错误,java,backwards-compatibility,serializable,Java,Backwards Compatibility,Serializable,我只是遇到了“WTF”类的错误:我更新了我的类的一个方法,并添加了一个方法。运行“我的程序”后,当程序试图打开并取消序列化最近保存的数据时(在方法更改之前),会弹出以下消息: 根据java文档对此的描述,java方法没有被序列化。那么为什么serialVersionUID也要考虑类方法呢 既然Java程序员似乎到处都在使用getter和setter,为什么不可能为serialVersionUID创建getter,这样我就可以实现自己的算法,只计算属性 ,但仅带有静态最终长serialVersio

我只是遇到了“WTF”类的错误:我更新了我的类的一个方法,并添加了一个方法。运行“我的程序”后,当程序试图打开并取消序列化最近保存的数据时(在方法更改之前),会弹出以下消息:

根据java文档对此的描述,java方法没有被序列化。那么为什么
serialVersionUID
也要考虑类方法呢

既然Java程序员似乎到处都在使用getter和setter,为什么不可能为
serialVersionUID
创建getter,这样我就可以实现自己的算法,只计算属性

,但仅带有
静态最终长serialVersionUID
值,该值要求我在更改类的属性时记住对其进行更改。

指示如果您不提供
serialVersionUID
,编译器将为您生成一个

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

根据

版本控制提出了一些关于类标识的基本问题,包括什么构成兼容的更改。兼容更改是不影响类与其调用方之间契约的更改

这里发生的事情是,编译器已经决定,您的代码的两个版本之间的差异需要一个新的
serialVersionUID
。如果您觉得对象(1)和对象(2)的实例中包含的状态是可互换的,那么您应该通过手动设置
serialVersionUID
并在这些更改之间保持不变来管理它

是的,您必须手动管理该类,并在更改管理类内部状态的机制时对其进行更改


作为注释,如果公共方法已经更改,则应该考虑该类的原始版本是否符合新版本相同的期望。如果希望将先前序列化状态中包含的数据加载到类的新版本中,可以使用静态构造函数方法以兼容的旧状态初始化新版本(新行为)。

基于java文档,他们建议尽可能多地使用custom
serialVersionUID
,因为默认算法将获取类实现的详细信息,并且据说结果因JVM实现而异

Java用来生成
serialVersionUID
的方法似乎也考虑了非私有方法(步骤7)。这解释了在实现中使用默认的
serialVersionUID
时出现的异常

编辑:
正如您所建议的,如果我们能够拥有自己的方法实现来实现这一点,而不是将
serialVersionUID
重写为
静态final long
,那就太好了。但我想他们不允许这样做,因为如果允许的话,这种方法的错误实现可能会使
serialVersionUID

的整个目的失效。这显然是Java端没有正确实现的东西<代码>类及其调用方与序列化无关,这是编译器应该检查的。如果您在没有方法的情况下取消类对使用方法的类的序列化,那么就不会有问题。我不确定我是否同意--如果我有一个
类狗
,它具有内部
字符串名称
和一个
方法bark()
,然后我将该类更改为具有一个新的
方法barkMyName()
,如果使用新类取消旧
狗的序列化,它将无法叫自己的名字。因此,调用方不应该期望能够将该消息发送到此实例。如果您希望能够将不带方法(旧)的类取消序列化为带方法(新)的类,则必须通过在两者之间保持相同的
serialVersionUID
来进行管理。要从Bloch的有效Java中添加,“如果您没有通过声明名为
serialVersionUID
static final long
字段明确指定此数字,则系统会在运行时通过对类应用复杂过程自动生成该数字。”。自动生成的值受类的名称、它继承的接口的名称及其所有公共和受保护的成员的影响。”(我的重点)Andy我不确定您是否正确地想象了这种情况。如果您使用
bark()的类的旧实现
并且您取消了对
狗的序列化
您并不真的期望狗能够
barkMyName
,因为该方法是n
java.io.InvalidClassException: cz.autoclient.settings.Settings; local class incompatible: stream classdesc serialVersionUID = 2404650814140543454, local class serialVersionUID = 4256355437298300223