java.io.InvalidClassException:本地类不兼容:

时间:2012-04-30 05:22:27

标签: java serialization client-server deserialization

我创建了客户端和服务器,然后在客户端添加了一个类用于序列化,然后只是转到我硬盘中客户端的文件夹并将其粘贴到服务器相应位置,classname.classclassname.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;
}

8 个答案:

答案 0 :(得分:35)

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

来自Serializable界面的docs

  

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

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

class MyClass implements Serializable {
    private static final long serialVersionUID = 6529685098267757690L;
    ...

答案 1 :(得分:2)

可能发生的一件事:

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

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

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

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

答案 2 :(得分:1)

如果使用的是Eclipse IDE,请检查Debug / Run配置。 在“类路径”选项卡上,选择运行器项目,然后单击“编辑”按钮。 必须检查仅包括导出的条目

答案 3 :(得分:0)

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

答案 4 :(得分:0)

java中的序列化并不是长期持久性或传输格式 - 它太脆弱了。由于类字节码和JVM存在最微小的差别,因此您的数据不再可读。为您的任务使用XML或JSON数据绑定(XStream快速且易于使用,并且有大量替代方案)

答案 5 :(得分:0)

异常消息清楚地表明,类版本(包括类元数据)也随着时间的推移而发生变化。换句话说,序列化期间的类结构在反序列化期间是不同的。这是最有可能的"继续"。

答案 6 :(得分:0)

如果您正在使用oc4j来部署耳朵。

确保在项目中设置了deploy.home =

的正确路径

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

oc4j需要在耳朵中重新加载新创建的类,以便服务器类和客户端类具有相同的serialVersionUID

答案 7 :(得分:0)

如果您使用的是 IntelliJ IDEA,请转到文件->无效缓存。这将清除可能导致此问题的所有缓存类。