背景
我有一个类,它没有覆盖任何序列化功能,也没有 serialVersionUID
,但它仍然被序列化、存储,然后反序列化。这是一个配置对象,当更改配置时,数据实际上是从配置 UI 中读取的,然后通常“从头开始”创建对象并序列化以进行存储。只有在使用时,才会通过反序列化创建对象。
现在有两个字段被添加到这个类中,它们不应该被序列化,但是......这当然会导致一些反序列化问题(NullPointerException 当字段在默认反序列化后保留为空时,破坏类不变量),解决了通过打开配置 UI 并保存配置,从而保存对象的正确序列化形式。
问题
现在,如果我以这些方式之一修改类以进行快速修复,从保存的配置数据反序列化对象会发生什么:
- 去掉这些字段,保存的数据是新版本的,里面有这些字段吗?
- 把这些字段改成transient,保存的数据是新版本的,里面有这些字段?
- 将这些字段更改为 transient ,保存的数据是旧版本,没有这些字段?
为了使这个更具体,假设添加的字段是:
private final Map<String, String> extraProperties = new HashMap<String, String>();
这要么从此类中删除,要么更改为 private final transient
字段。
附言。不用告诉我,自定义序列化代码应该可能被添加,然后整个事情应该可能被重构,以将持久性和 transient 数据分离到不同的类.. .
最佳答案
删除(或临时化)这些您不想序列化的冗余字段。然后尝试反序列化加载旧版本,其中存在现已删除的非 transient 字段。这当然会导致错误,因为类 serialVersionUID
现在不同了。然而,旧的和新的 serialVersionUID
都应该包含在消息中。
现在只需在您的类中定义 private static long serialVersionUID =
,将其设置为旧值。文件中有多余字段的类内容将被加载,这些多余字段的值将被忽略。
但是您现在遇到了另一个问题:您可能已经保存了两种不同类型的文件:旧版本和新版本。它们将具有不同的 serialVersionUID,因此我们可以加载其中一个,但不能同时加载两者。 serialVersionUID 是最终的,但也许您仍然可以设置和探测不同的值作为 described here .
从序列化的角度来看,将字段更改为 transient 与删除字段是一样的。它不会被存储,也不会被加载。但是,如果 serialVersionUID
未固定,则将先前的非 transient 字段声明为 transient 将更改它。
如果逐项,如果 serialVersionUID 现在是硬编码并且与文件中的 serialVersionUID 相匹配,那么您的问题的答案是:
- 没有。
- 没有。
- 没有。
作为“无”我的意思是类被反序列化而没有为 transient 字段赋值(如果存在)并且没有错误报告。
如果 serialVersionUID 不匹配,则抛出异常,即使类的其余部分匹配也是如此。
关于Java反序列化,将字段更改为 transient ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14274245/