我有一个来自旧 Java 代码的对象,现在我更改了序列化的对象代码。我希望能够同时读取旧文件和新文件。我需要 readObject 中的分支语句来执行以下操作:
if (next object is int -- just poking, it might be an Object)
{
// we know we are in version 1
} else {
// read new version of object
}
那有可能吗?
我有一个来自旧 Java 代码的对象,现在我更改了序列化的对象代码。我希望能够同时读取旧文件和新文件。我需要 readObject 中的分支语句来执行以下操作:
if (next object is int -- just poking, it might be an Object)
{
// we know we are in version 1
} else {
// read new version of object
}
那有可能吗?
if (object instanceof Integer) {
... Do stuff
} else {
... Do other stuff
}
编辑:我想我应该对此进行扩展。您可以使用检查对象类型,instanceof
但我不确定是否能够使用int
或char
.
最简单的方法是保留旧的成员变量和它们的旧类型,并为新类型添加新的成员变量。此外,您必须保持类的 serialVersionUID 相同。然后,您的 readObject() 实现可以进行任何必要的操作以将旧数据转换为新数据。
原始对象:
public class MyObject {
private static final long serialVersionUID = 1234L;
private int _someVal;
}
新版本:
public class MyObject {
private static final long serialVersionUID = 1234L;
private int _someVal; //obsolete
private String _newSomeVal;
private void readObject(java.io.ObjectInputStream in)
throws IOException, ClassNotFoundException
{
in.defaultReadObject();
if(_someVal != 0) {
// translate _someVal to _newSomeVal
}
}
}
我相信使用 customObjectStreamField[] serialPersistentFields
和.ObjectInputStream.GetField
ObjectOutputStream.PutField
好的,所以基本上问题是“我们如何检查ObjectInputStream
下一个字段是原始字段还是对象?” 据我所知,答案是:你不能。
这意味着我能看到的保持向后兼容性的最佳解决方案是永远不要从原始版本中删除原语 - 保留无用的信息会稍微扩大大小,但否则这很容易。
要添加新字段,我可以看到两种方法:
保持之前的消息格式相同,只在最后添加新对象 - 然后您可以通过消息大小轻松区分不同版本(或者更准确地说,当您获得 v1 对象时读取 v2 的数据时您将获得 IOException)。这要简单得多,而且通常是首选。
您可以将对象从 v1 更改为 v2,然后进行简单instanceof
检查。如果要添加原语是存储它们的包装器版本(即Integer
等)。可以为您节省一些字节,但 Java 的序列化协议从一开始就效率不高,所以这实际上是不必要的复杂。
ObjectInputStream
将加载并创建正确类的实例。
object = ois.readObject();
if (object instanceof YourNewShiny ){
// new style object
} else if (object instanceof YourOldBusted ){
// convert YourOldBusted to YourNewShiny
} else {
throw new ToyOutOfPram();
}
如果您有一个新类,这一切都很好,但是如果您以不兼容的方式更改了您的类,以至于ObjectInputStream
无法将类的旧版本反序列化为新形式。如果是这种情况,你就吃饱了。
选项:
ObjectInputStream
以检测您的类类型(您可以使用 serialVersionId 来加强类型)只有第一个对我来说似乎是个好主意。