Java序列化和反序列化

8

我有一个如下的对象:

    public class Records implements java.io.Serializable{
        private int cId;
        private int pId;
        private int vlaue;
        private int tag;

        public Records(int c, int p, int v, int t){
                this.cId=c;
                this.pId=p;
                this.value=v;
                this.tag=t;
        }
}

我已经收集了大量的数据,像上面的类一样构造了对象,并将它们序列化到磁盘。

我忘记在类文件中包含访问每个对象值的方法,例如,要访问特定对象的cId值。

我修改了类定义以添加这些方法,但是我无法将对象反序列化回Records类,并获得此运行时错误:

java.io.InvalidClassException: Records; local class incompatible: stream classdesc serialVersionUID = -1232612718276774474, local class serialVersionUID = -8244963718951538904
    at java.io.ObjectStreamClass.initNonProxy(ObjectStreamClass.java:579)
    at java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.java:1600)
    at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1513)
    at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1749)
    at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1346)
    at java.io.ObjectInputStream.readObject(ObjectInputStream.java:368)
    at DeSerialise.main(DeSerialise.java:21)

我认为我需要告诉Java它们是同一定义,并修改serialVersionUID,但不确定如何操作?欢迎任何想法!


1
您可以在此问题的链接中找到对您问题的很好的解释:https://dev59.com/Y3VC5IYBdhLWcg3wdw65 - Tom
4个回答

9

尝试在你的类中添加以下内容:

private static final long serialVersionUID = -1232612718276774474L;

这将使您的类的serialVersionUID与在实例序列化时使用的编译器生成的值保持一致。
下面是来自文档的一句话值得一读(重点是我的):

The serialization runtime associates with each serializable class a version number, called a serialVersionUID, which is used during deserialization to verify that the sender and receiver of a serialized object have loaded classes for that object that are compatible with respect to serialization. If the receiver has loaded a class for the object that has a different serialVersionUID than that of the corresponding sender's class, then deserialization will result in an InvalidClassException. A serializable class can declare its own serialVersionUID explicitly by declaring a field named "serialVersionUID" that must be static, final, and of type long:

ANY-ACCESS-MODIFIER static final long serialVersionUID = 42L;

If a serializable class does not explicitly declare a serialVersionUID, then the serialization runtime will calculate a default serialVersionUID value for that class based on various aspects of the class, as described in the Java(TM) Object Serialization Specification. However, it is strongly recommended that all serializable classes explicitly declare serialVersionUID values, since the default serialVersionUID computation is highly sensitive to class details that may vary depending on compiler implementations, and can thus result in unexpected InvalidClassExceptions during deserialization. Therefore, to guarantee a consistent serialVersionUID value across different java compiler implementations, a serializable class must declare an explicit serialVersionUID value. It is also strongly advised that explicit serialVersionUID declarations use the private modifier where possible, since such declarations apply only to the immediately declaring class--serialVersionUID fields are not useful as inherited members. Array classes cannot declare an explicit serialVersionUID, so they always have the default computed value, but the requirement for matching serialVersionUID values is waived for array classes.


0
您可以在您的类中如下声明序列版本 ID:
private static final long serialVersionUID = -1232612718276774474L;

1
添加一个随机的serialVersionUID是没有帮助的。 - JB Nizet
1
如果您不包含序列版本UID,Java会为您生成一个。在反序列化时,它会检查类的序列版本UID是否与存储在序列化字节中的UID匹配。因此,如果您想反序列化字节数组,则您的类必须具有与Java生成并写入对象序列化时字节数组中的UID相同的UID。当然,类的字段也必须兼容。 - JB Nizet
添加一个随机ID无法帮助反序列化已具有不同ID的现有序列化对象,但对于添加随机ID后进行序列化的任何对象都可以正常工作。 - Jerry B
@JrryB 当然可以,但是这个问题是关于前一种情况的,而错误消息提供了所需的正确值。所以这不是一个答案。 - user207421
1
@foampile 你可以将其省略并从第一个异常中获取,就像这里一样,或者你可以使用 serialver 工具。 - user207421
显示剩余4条评论

0

非常重要的是为类指定serialversionId,否则很难识别序列化的类。

如果您这样做,可以创建新的序列化对象而不是使用旧的序列化对象。

Eclipse IDE将自动生成serialversionId,请尝试使用它。


0
问题在于您在类中序列化数据时没有定义serialVersionUID。添加setter和getter是可以的,不会影响序列化,但是当您重新编译类时,编译器可能会生成另一个UID,这将导致在尝试反序列化数据时出现异常。如果需要实际反序列化使用第一个版本类序列化的数据,则需要知道编译器第一次生成的UID:这可以在错误消息中看到,因此您需要将serialVersionUID设置为-1232612718276774474L。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接