Java序列化-java.io.InvalidClassException本地类不兼容[重复]
Posted
技术标签:
【中文标题】Java序列化-java.io.InvalidClassException本地类不兼容[重复]【英文标题】:Java serialization - java.io.InvalidClassException local class incompatible [duplicate] 【发布时间】:2012-01-10 06:30:54 【问题描述】:我有一个实现 Serializable 的公共类,它由多个其他类扩展。以前只有那些子类被序列化过——从来没有超类。
超类定义了一个serialVersionUID。
我不确定它是否重要,但它没有标记为私有,而是它只是具有默认保护 - 你可能会说它是包保护的
static final long serialVersionUID = -7588980448693010399L;
父类和任何子类都实现了 readObject 或 writeObject,并且没有一个子类具有显式定义的 serialVersionUID。我认为在超类中定义一个就足够了。
尽管如此,在回读之前序列化的对象之前一切都很好,直到一个新的实例变量 List/ArrayList 以及一个新方法被添加到超类中,并且一些私有实例变量被添加到一个它的子类。
现在,当尝试回读以前序列化的对象时,会引发异常。与此类似的一个:
com.SomeCompany.SomeSubClass; local class incompatible: stream classdesc serialVersionUID = 1597316331807173261, local class serialVersionUID = -3344057582987646196
我假设这是因为默认的serialVersionUID(因为我没有在任何子类中声明一个而使用)现在由于超类和一个子类的变化而发生了变化。
我们将不胜感激有关如何摆脱这种困境的建议。我假设我需要实现 readObject 和 writeObject,但除了调用 defaultReadObject() 和 defaultWriteObject(),我不确定我需要做什么。我也不知道是否需要将 serialVerisonUIDs 添加到所有子类,或者是否需要每个子类实现 readObject 和 writeObject,或者我是否可以只实现一次,假设我需要在超类中实现。
【问题讨论】:
参见。 ***.com/questions/10378855/… 如果以后有人遇到问题:只需删除项目中存在的 .obj 文件,然后再次尝试运行该项目。 【参考方案1】:这里的简短回答是,如果您未指定序列号,则通过哈希计算序列号。 (静态成员不是继承的——它们是静态的,只有 (1) 个并且它属于该类)。
http://docs.oracle.com/javase/6/docs/platform/serialization/spec/class.html
getSerialVersionUID 方法返回 this 的 serialVersionUID 班级。请参阅第 4.6 节,“流唯一标识符”。如果不 由类指定,返回的值是从 使用安全哈希的类的名称、接口、方法和字段 美国国家标准协会定义的算法 (SHA)。
如果您更改一个类或其层次结构,您的哈希值将有所不同。这是一件好事。您的对象现在不同了,因为它们有不同的成员。因此,如果你从它的序列化形式读回它,它实际上是一个不同的对象——因此是例外。
长答案是序列化非常有用,但可能不应该用于持久性,除非没有其他方法可以做到这一点。这是一条危险的道路,特别是因为您正在经历的事情。对于纯 Java 项目,您应该考虑数据库、XML、文件格式以及可能的 JPA 或其他持久性结构。
【讨论】:
【参考方案2】:@DanielChapman 对 serialVersionUID 给出了很好的解释,但没有解决方案。解决方案是这样的:在所有 old 类上运行 serialver
程序。将这些serialVersionUID
值放入您的当前 版本的类中。只要当前的类与旧版本串行兼容,就可以了。 (未来代码的注意事项:您应该始终在 所有 Serializable
类上使用 serialVersionUID
)
如果新版本不串行兼容,那么您需要使用自定义readObject
实现来做一些魔术(如果您尝试编写,则只需要自定义writeObject
em>new 与旧代码兼容的类数据)。一般来说,添加或删除类字段不会使类序列不兼容。更改现有字段的类型通常会。
当然,即使新类 与串行兼容,您可能仍需要自定义readObject
实现。如果您想填写从旧版本的类保存的数据中缺少的任何新字段,您可能需要这个(例如,您有一个新的 List 字段,您想在加载旧的类数据时将其初始化为空列表)。
【讨论】:
...或者如果您没有旧类,请从异常消息中获取旧的 serialVersionUID,并根据需要重复。 您的回答和truthealitiy's 组合包含所有相关详细信息。也许问题可以合并?【参考方案3】:对我来说,我忘了添加默认序列号。
private static final long serialVersionUID = 1L;
【讨论】:
+1;原则上,它会在创建新的“实体类”文件时自动添加在 Netbeans 下。【参考方案4】:这对我有用:
如果你将你的序列化类对象写入一个文件,然后对文件进行一些更改并编译它,然后你尝试读取一个对象,那么就会发生这种情况。
所以,如果一个类被修改和重新编译,则将必要的对象再次写入文件。
PS:这不是解决方案;本来是一种解决方法。
【讨论】:
没有必要这样做,或者丢失所有现有的序列化。查看其他答案。 这是一种解决方法,而不是解决方案。以上是关于Java序列化-java.io.InvalidClassException本地类不兼容[重复]的主要内容,如果未能解决你的问题,请参考以下文章