关于序列化、serialVersionUID和不兼容的类

9
我看到这里有几个相关的问题和答案,但它们似乎没有帮助。所以我想在这里发布一个单独的问题:
我有一个可序列化的类MyDataClass,其中包含几个更多的可序列化内部类。我使用FileOutputStream和ObjectOutputStream将其保存到文件中。当读取它时,有时会出现异常(可能是ClassNotFoundException或InvalidClassException,但我不确定),异常消息如下:
12-01 18:44:16.479: D/My App Name(534): ***** exception occurred 
com.xyz.myapp.lib.am; Incompatible class (SUID): com.xyz.myapp.lib.am: 
static final long serialVersionUID =3894560643019408205L; but expected 
com.xyz.myapp.lib.am: static final long serialVersionUID =-4215454881436014736L;

MyDataClass 大致如下:

public static class MyDataClass implements Serializable {

    private static final long serialVersionUID = 0x98F22BF5;
    .....
    public boolean bNoTitle;
    public short syncOption;
    .....

    public class InnerClass implements Serializable {
        private static final long serialVersionUID = 0x99D32720;
        double premium;
        double interest;
    }
}

然后我使用以下代码来读取它:
MyDataClass oc;
FileInputStream fin = new FileInputStream(dataFile);
ObjectInputStream ois = new ObjectInputStream(fin);
oc = (MyDataClass)ois.readObject();
ois.close();
fin.close();

readObject方法有时会引发异常,但并非每次都会出现。我在某个地方读到,实际写入文件的 serialVersionUID 不是我在代码中分配的那个。因此,在读回时,UID 不匹配,从而导致异常。如果是这样,我该如何确保没有异常,并按预期读取对象?谢谢。
编辑:从 Eclipse 进行调试时,一切正常。但是在使用 ant 构建后,问题就会出现。但并非每次经过 ant 构建后都会出现问题,只是偶尔会有。
编辑:在另一个帖子中,我看到了这样一段话:
“你是从文件中读取的吗?如果是这样,那么现在添加 serialVersionUID 是无关紧要的,它与存储在文件中的不同,这会导致异常。一个快速的解决方法是将 serialVersionUID 设置为 4209360273818925922L,这似乎是 Java 在您保存那些对象时自动生成的 serialVersionUID。”
当用户使用应用程序时,我的文件将被多次保存/读取。如果 Java 每次文件保存时都分配一个不同的 UID,那么我怎样才能提前在代码中设置一个静态 UID?我需要一个真正静态的 UID,即使经过 ant 构建也不会改变。

你有意将整数分配为serialVersionUID吗?一般来说这不应该是一个问题,但通常你应该使用长整型值。 - Robert
@Robert,这并不是故意的,只是恰巧这样发生了。我认为这没有任何问题。 - wwyt
2个回答

2

我同意AKJ的观点:

我认为你遇到的第一个问题“找不到类” - 你可能正在一个不知道这个类的环境中反序列化该类。也有可能你有两个拷贝该类的环境。

无论如何,序列化的UID工作方式如下: 如果你没有指定一个UID,它将在每次编译/构建时自动生成一个 - 否则,如果你指定了一个UID,则该UID就是UID。

请注意,AJK可能是正确的,而你却不知道 - 除非在声明时指定transient,否则默认情况下会序列化你类的每个成员变量。因此,如果你有short、long、String、myClass或其他类型的变量,它们都将通过序列化。根据上面的解释,如果没有设置常量UID,则每次编译都会得到不同的UID - 这很可能导致你的问题。

祝好运。


1

由于您明确声明了serialVersionUID,只要serialVersionUID没有更改(且类没有发生重大更改),序列化和反序列化就不会有问题。

从异常消息中可以感觉到,您可能正在序列化某个成员类,但该类没有显式的serial version UID,因此您可能需要在该类中明确声明serialVersionUID。

另一个可能性是,您可能意外地尝试读取一个在您放置显式serialVersionUID之前保存的文件。


感谢您的回复。这些猜测非常聪明,尤其是第二个。但我相当确定这些不是原因。但还是谢谢您的指点。 - wwyt

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