【发布时间】:2016-08-01 13:34:15
【问题描述】:
Java 语言从添加枚举中受益匪浅;但不幸的是,它们在具有不同代码级别的系统之间发送序列化对象时效果不佳。
示例:假设您有两个系统 A 和 B。它们都以相同的代码级别开始,但在某个时间点开始在不同的时间点看到代码更新。现在假设有一些
public enum Whatever { FIRST; }
还有其他对象保留对该枚举常量的引用。这些对象被序列化并从 A 发送到 B,反之亦然。现在考虑 B 有一个更新版本的whatever
public enum Whatever { FIRST; SECOND }
然后:
class SomethingElse implements Serializable { ...
private final Whatever theWhatever;
SomethingElse(Whatever theWhatever) {
this.theWhatever = theWhatever; ..
被实例化...
SomethingElse somethin = new SomethingElse(Whatever.SECOND)
然后序列化并发送到 A(例如作为某些 RMI 调用的结果)。这很糟糕,因为现在在 A 的反序列化过程中会出现错误:A 知道 What enum 类,但在没有 SECOND 的版本中。
我们很难想到这一点;现在我非常渴望将枚举用于实际上“非常适合枚举”的情况;仅仅是因为我知道以后我不能轻易地扩展现有的枚举。
现在我想知道:是否有(好的)策略来避免此类与枚举的兼容性问题?或者我真的必须回到“预枚举”时代吗?并且不使用枚举,但必须依赖我在所有地方都使用纯字符串的解决方案?
更新:请注意,使用 serialversionuid 在这里根本没有帮助。那件事只会帮助您做出“更明显”的不兼容更改。但重点是:我不在乎为什么反序列化会失败——因为我必须避免它发生。而且我也无法改变我们序列化对象的方式。我们正在做 RMI;我们正在序列化为二进制;我没有办法改变它。
【问题讨论】:
-
这不是任何课程的问题吗?如果您在较新版本中更改字段,则旧版本的反序列化将失败。
-
不一定。添加字段是完全有效的操作。如果你使用纯字符串,你显然会松散编译时间检查;但是如果对象字段是字符串,那么该字段可以携带 any 值而不会导致此类问题。
-
你可以使用常量——它们可以很好地序列化,并且它们有许多类似枚举的属性
-
我同意@DanielM。对两个系统使用常量或使用相同的
Whatever枚举定义。 -
这更多是 Java 序列化的问题,而不是枚举的问题。序列化与代码紧密耦合,这使得它不适合系统之间甚至同一系统的不同版本之间的长期存储和互操作性。使用 JSON 或 XML 等标准格式而不是 Java 序列化以实现更松散的耦合。
标签: java serialization enums