java.io.InvalidClassException:

2022-09-04 23:54:12
InvalidClassException: local class incompatible: stream classdesc serialVersionUID = -196410440475012755, local class serialVersionUID = -6675950253085108747

在以下场景中,我使用 InvalidClassException 进行结构处理。在这里,我的 EAR 安装在 4 个 Websphere 应用程序服务器中,执行由此服务器共享。有时我从POJO类中得到异常InvalidClassException,这是实现可序列化接口。请提供任何线索。我对此一无所知。


答案 1

当您实现 java.io.Serializable 接口以使类可序列化时,编译器会查找一个名为 long 类型的名为“serialVersionUID”的静态最终字段。如果类没有显式声明此字段,则编译器将创建一个这样的字段,并为其分配一个值,该值来自串行VersionUID的实现相关计算。此计算取决于类的各个方面,并遵循 Sun 给出的对象序列化规范。但是,不保证该值在所有编译器实现中都相同。

此值用于检查类与序列化相关的兼容性,这是在反序列化保存的对象时完成的。序列化运行时验证发送方类(用于在流上保存对象的状态)和接收方类(用于还原对象的类,可能在其他某个系统中)的 serialVersionUID 是否完全相同。如果接收方系统加载的类具有其他一些串行VersionUID,而不是序列化过程中使用的类,那么我们得到一个InvalidClassException。

注意 -- 强烈建议您在要使序列化的所有类中显式声明并初始化 long 类型和名为“serialVersionUID”的静态最后一个字段,而不是依赖于此字段的值的默认计算。此计算非常敏感,并且可能因编译器实现而异,因此,即使对于同一类,您也可能会因为对序列化过程的发送方和接收方端使用了不同的编译器实现而获得 InvalidClassException。

在大多数情况下,您将仅对此字段使用“private”访问说明符,因为声明通常仅适用于声明它的类,并且我们真的不需要在子类中继承此字段或从外部访问它。因此,我们几乎没有任何理由不将其“保密”。


答案 2

当您尝试反序列化使用同一类的不兼容(通常是更早)版本序列化的对象时,您会收到该异常。

如果未在类实现 中显式指定 a,则将基于类的(非)字段生成一个值。这样做是为了确保不会恢复任何部分对象(最好是失败,而不是盲目地继续处理可能损坏的对象)。serialVersionUIDSerializabletransient

在 Web 应用程序系统中,序列化的常见用途是用于会话:如果将值放入会话中,则它最终可能会被序列化(用于群集支持或只是为了获取持久会话)。

因此,要么保持版本之间的所有类兼容,要么确保不还原它们不会破坏应用程序(即不要以这种方式存储重要信息)。