尝试保存和读取文件时获取java.io.InvalidClassException

时间:2014-12-15 17:36:44

标签: java serialization io

public static void save(Settings settings) {
    try {
        ObjectOutputStream os = 
                new ObjectOutputStream(
                        new FileOutputStream(settingsFile));
        os.writeObject(settings);
        os.close();
    } catch(Exception e) {
        e.printStackTrace();
    }
}

这是将类设置保存到文件的代码。

public static Settings load() {
    try {
        ObjectInputStream is = 
                new ObjectInputStream(
                        new FileInputStream(settingsFile));
        Settings settings = (Settings) is.readObject();
        is.close();
        return settings;
    } catch(Exception e) {
        e.printStackTrace();
    }
    return null;
}

此代码将读取文件并返回转换为Settings

的Object

错误是获取

Settings settings = (Settings) is.readObject();    

并且StackTrace是

java.io.InvalidClassException: com.Settings; local class incompatible: stream classdesc serialVersionUID = 5215625451621355973, local class serialVersionUID = -6263468811172060812
at java.io.ObjectStreamClass.initNonProxy(Unknown Source)
at java.io.ObjectInputStream.readNonProxyDesc(Unknown Source)
at java.io.ObjectInputStream.readClassDesc(Unknown Source)
at java.io.ObjectInputStream.readOrdinaryObject(Unknown Source)
at java.io.ObjectInputStream.readObject0(Unknown Source)
at java.io.ObjectInputStream.readObject(Unknown Source)
at com.Settings.load(Settings.java:51)
at com.Main.main(Main.java:23)

我不完全确定为什么我收到此错误,因为写入文件的对象是“设置”,正在读取的对象也是“设置”。任何帮助将不胜感激

2 个答案:

答案 0 :(得分:2)

您序列化的类的版本为X,您使用的当前Settings类的版本为Y(其中,版本是每个Serializable具有的版本UID ,即使你没有定义一个,它也会由Java通过查看你的类内部来生成)

将来在您使用Serializable的类中定义private (no matter, it could be public/protected too) static final long serialVersionUID时,使用值(例如1L)将避免此问题。

要修复您的例外,现在定义一个值为serialVersionUID的{​​{1}}(因此它们将匹配)并对其进行反序列化。 (并且它不安全。)

无论如何,我只是应该使用新的UID值(1L?)对其进行重新序列化以使其始终兼容,因为如果您不提供此值,则可以鼓励其他人出错。

Serializable JavaDoc对我的解释比我好。

  

序列化运行时与每个可序列化的类a关联   版本号,称为serialVersionUID,在此期间使用   反序列化以验证序列化的发送方和接收方   object已加载与该对象兼容的类   尊重序列化。如果接收器已加载了一个类   具有与其不同的serialVersionUID的对象   相应的发件人的类,然后反序列化将导致   InvalidClassException。可序列化的类可以声明它自己的类   serialVersionUID通过声明一个名为的字段显式地显示   "的serialVersionUID"必须是static,final和long类型:

5215625451621355973
     

如果是   serializable类没有显式声明serialVersionUID,   然后序列化运行时将计算默认值   该类的serialVersionUID值基于该方面的各个方面   class,如Java(TM)对象序列化中所述   规格。但是,强烈建议所有人   可序列化类显式声明serialVersionUID值,因为   默认的serialVersionUID计算对类非常敏感   细节可能因编译器实现而异,并且可以   因此导致意外的InvalidClassExceptions期间   反序列化。因此,要保证一致的serialVersionUID   不同java编译器实现的值,可序列化   class必须声明一个显式的serialVersionUID值。也是   强烈建议显式serialVersionUID声明使用   尽可能使用私有修饰符,因为此类声明仅适用于   立即声明的类 - serialVersionUID字段不是   作为继承成员有用。数组类不能声明显式   serialVersionUID,所以它们总是有默认的计算值,但是   免除匹配serialVersionUID值的要求   数组类。

答案 1 :(得分:0)

检查代码中的serialVersionUID - 这是Serializable类的通用版本标识符。

e.g。 static final long serialVersionUID = 1L;

反序列化使用此数字来确保加载的类与序列化对象完全对应。如果未找到匹配项,则抛出InvalidClassException