我有一个来自旧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
}
有可能吗?
答案 0 :(得分:2)
if (object instanceof Integer) {
... Do stuff
} else {
... Do other stuff
}
编辑:我想我应该扩展这一点。您可以使用instanceof
检查对象类型,但我不确定是否能够使用int
或char
这样的原型。
答案 1 :(得分:1)
最简单的方法是使用旧类型保留旧成员变量,并为新类型添加新成员变量。此外,您必须保持类的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
}
}
}
我相信使用自定义ObjectStreamField[] serialPersistentFields
,ObjectInputStream.GetField
和ObjectOutputStream.PutField
还有更复杂的选项。
答案 2 :(得分:1)
好的基本上问题是“我们如何检查ObjectInputStream
下一个字段是基元还是对象?”而据我所知,答案是:你不能。
这意味着我可以看到保持向后兼容性的最佳解决方案是永远不会从原始版本中删除原语 - 保持无用的信息稍微大一点,但这样很容易。
要添加新字段,我可以看到两种方式:
保持较早的消息格式相同,只在最后添加新对象 - 然后您可以通过消息大小轻松区分不同的版本(或者更准确地说,当您获取v2的数据时,您将获得IOException一个v1对象)。这更简单,通常更受欢迎。
您可以将对象从v1更改为v2,然后执行简单的instanceof
检查。如果你想添加原语是存储他们的包装器版本(即Integer
等)。可以节省一些字节,但Java的序列化协议从一开始就没有效率,所以真的不必要复杂。
答案 3 :(得分:0)
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来强化该类型)对我来说,只有第一个似乎是个好主意。