java - 是否有内置方法来检测序列化的 java 对象是否缺少字段?

标签 java serializable

我正在对我的可序列化类进行兼容修改,即添加一些基本字段( boolean 型、长型)。我的类是服务器提供的数据的客户端表示。

当我从文件加载类时,我需要能够检测加载的类是否由早期版本保存,即它缺少一些在加载时 java 设置为默认值的字段。如果是这种情况,我的应用程序仍然可以工作,但是当客户端有网络连接时,我想从服务器获取新字段。

Java 是否有任何内置方法来检测是否加载了缺少字段的类?

(我意识到我可以用“版本”实例成员手动解决这个问题;我希望 Java 有一些内置的东西)

最佳答案

您可以覆盖 Serializable 接口(interface)的 readObject() 方法来自定义处理类的反序列化。

请注意,强烈建议您在实现 Serializable 时也包含一个 serialVersionUID:

private static final long serialVersionUID = 1;

如果你没有定义它,一个是从你的类成员的哈希创建的...那么如果你以后按照你的描述添加东西,UID 将不匹配并且 Java 不会让你重新加载旧数据.

更多信息来自此处的可序列化文档:http://docs.oracle.com/javase/6/docs/api/java/io/Serializable.html


有关处理非破坏性更改的更多信息:

如果实现之间存在重大更改,这使得使用新代码反序列化旧版本变得毫无意义,那么您真的应该只更改 serialVersionUID。

如果您通过添加一些字段对您的类进行非破坏性更改,则不应更改 serialVersionUID。如果原始类没有指定的 serialVersionUID,则会自动为您生成一个,并且会在您的新实现中自动生成一个新的,与旧的不匹配

当你尝试反序列化serialVersionUID不匹配的旧版本时,系统将抛出java.io.InvalidClassException。带有此异常的错误消息将告诉您旧的 serialVersionUID 是什么以及新的是什么。

然后您可以修改您的类,使其具有与旧版本匹配的明确指定的 serialVersionUID,从而允许您反序列化旧版本和新版本而不会抛出异常。

在反序列化旧版本实例时,运行时会将任何新的原始成员设置为其默认值

如果您想检测是否反序列化了类的旧版本或新版本,您可以检查一个默认值,该默认值在您的 readObject() 实现中不应该是默认值。

这是一个例子:

// add a new private field to the modified class for tracking version:
private int myNewVersionFlag = 123;

// then in your readObject implementation:
private void readObject(java.io.ObjectInputStream stream)
     throws IOException, ClassNotFoundException {

    stream.defaultReadObject();

    if( this.myNewVersionFlag == 0 ) {
        // if we get here the object being deserialized must
        // be an old version, so now set sensible defaults 
        // for the new params or whatever...
    }

}

还有其他更复杂的方法,包括实现您自己的 ObjectInputStream 子类,但总的来说,我发现简单地拥有一个不应该为零的版本字段对于许多用例来说是简单且足够的。

总结

  • 如果您始终指定自己的 serialVersionUID,您的代码会更高效(它不必自动生成哈希代码)并且您能够更好地显式处理 future 的类更改。

  • 只有在您的更改中断时才应更改此值,这意味着无法反序列化旧版本的类,因为类的新功能不可能有合理的默认值。

  • 如果您有自己的私有(private)成员来跟踪版本号,您可以在 readObject() 中使用它,以便在需要时反序列化旧实例时将合理的默认值插入新变量。

最后,Java 序列化规范涵盖了您想了解的有关反序列化(但不敢问)的所有内容:

http://docs.oracle.com/javase/7/docs/platform/serialization/spec/serialTOC.html

关于java - 是否有内置方法来检测序列化的 java 对象是否缺少字段?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23976626/

相关文章:

具有原始值(或 Double)的 Java 泛型 `capture<?>`

java - Gradle 和 Spring 的几个模块

java - Java 中可序列化的工作

java - 在不可序列化的类中使用 transient 关键字

java - GWT 对象序列化

java - 小数格式与字符串格式

Java Spring STOMP : Set broker IP

Android应用更新不丢失数据

java - 我的 Spring Boot 服务器返回 406 Http 错误代码

java - 什么时候 Java 对象可序列化但不可克隆才有意义?