53

我创建了客户端和服务器,然后在客户端添加了一个用于序列化目的的类,然后只需转到我硬盘中客户端的文件夹并将其复制粘贴到服务器相应的位置,两者都classname.class分别classname.java

它在我自己的笔记本电脑上运行良好,但是当我想在其他系统上继续工作时,当我打开项目文件夹并且客户端尝试连接到服务器后,出现以下错误:

Exception in thread "main" java.io.InvalidClassException: projectname.clasname; local class incompatible: stream classdesc serialVersionUID = -6009442170907349114, local class serialVersionUID = 6529685098267757690
    at java.io.ObjectStreamClass.initNonProxy(ObjectStreamClass.java:562)
    at java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.java:1582)
    at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1495)
    at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1731)
    at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1328)
    at java.io.ObjectInputStream.readObject(ObjectInputStream.java:350)

到底是怎么回事?是因为我使用旧版本的 IDE 运行程序吗?

编辑

import java.io.Serializable;
import java.net.URL;

public class KeyAdr implements Serializable {
  private static final long serialVersionUID = 6529685098267757690L;

  public URL adr;
  public String key;
}
4

8 回答 8

73

如果一个类没有private static final long serialVersionUID在代码中显式定义a,它将自动生成,并且不能保证不同的机器会生成相同的id;看起来这正是发生的事情。此外,如果类以任何方式不同(使用不同版本的类),自动生成serialVersionUID的 s 也会不同。

Serializable界面的文档

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

您应该serialVersionUID在类定义中定义 a,例如:

class MyClass implements Serializable {
    private static final long serialVersionUID = 6529685098267757690L;
    ...
于 2012-04-30T05:29:08.307 回答
8

可能发生的一件事:

  • 1:您使用给定的库 A(版本 X)创建序列化数据
  • 2:然后您尝试使用相同的库 A(但版本 Y)读取此数据

因此,在版本 X 的编译时,JVM 将生成第一个 Serial ID(用于版本 X),并且它将对另一个版本 Y(另一个 Serial ID)执行相同的操作。

当您的程序尝试反序列化数据时,它不能,因为这两个类没有相同的序列号,并且您的程序不能保证两个序列化对象对应于相同的类格式。

假设您同时更改了构造函数,这对您来说应该是有意义的。

于 2018-03-14T09:52:48.410 回答
1

如果您使用的是 Eclipse IDE,请检查您的 Debug/Run 配置。在 Classpath 选项卡中,选择运行器项目并单击 Edit 按钮。 必须选中仅包括导出的条目。

于 2020-02-03T08:12:17.963 回答
0

异常消息清楚地表明,将包括类元数据的类版本随着时间的推移发生了变化。也就是说,序列化时的类结构在反序列化时是不一样的。这很可能是“正在发生”的事情。

于 2015-03-08T15:39:23.203 回答
0

java中的序列化并不意味着长期持久性或传输格式——它太脆弱了。类字节码和 JVM 稍有不同,您的数据就不再可读。为您的任务使用 XML 或 JSON 数据绑定(XStream快速且易于使用,并且有很多替代方案)

于 2012-04-30T06:05:51.573 回答
0

我相信发生这种情况是因为您在客户端和服务器上使用了同一类的不同版本。它可以是不同的数据字段或方法

于 2012-04-30T05:29:35.590 回答
0

如果您使用 IntelliJ IDEA,请转到 File->Invalidate Caches。这将清除任何可能导致此问题的缓存类。

于 2021-07-06T13:49:12.343 回答
0

如果您使用 oc4j 部署耳朵。

确保在项目中为 deploy.home= 设置正确的路径

您可以在 common.properties 文件中找到 deploy.home

oc4j需要重新加载ear中新创建的类,使服务端类和客户端类具有相同的serialVersionUID

于 2019-07-24T07:31:59.130 回答