Java自定义序列化
我有一个对象,其中包含一些我想要序列化的不可序列化字段。它们来自一个单独的API,我无法更改,因此使它们可序列化不是一个选项。主要问题是Location类。它包含我需要的四个可以序列化的东西,所有int。如何使用read/writeObject创建自定义序列化方法,该方法可以执行以下操作:Java自定义序列化,java,serialization,Java,Serialization,我有一个对象,其中包含一些我想要序列化的不可序列化字段。它们来自一个单独的API,我无法更改,因此使它们可序列化不是一个选项。主要问题是Location类。它包含我需要的四个可以序列化的东西,所有int。如何使用read/writeObject创建自定义序列化方法,该方法可以执行以下操作: // writeObject: List<Integer> loc = new ArrayList<Integer>(); loc.add(location.x); loc.add(l
// writeObject:
List<Integer> loc = new ArrayList<Integer>();
loc.add(location.x);
loc.add(location.y);
loc.add(location.z);
loc.add(location.uid);
// ... serialization code
// readObject:
List<Integer> loc = deserialize(); // Replace with real deserialization
location = new Location(loc.get(0), loc.get(1), loc.get(2), loc.get(3));
// ... more code
//writeObject:
List loc=new ArrayList();
位置添加(位置x);
位置添加(位置y);
位置添加(位置z);
loc.add(location.uid);
// ... 序列化代码
//readObject:
List loc=反序列化();//替换为真正的反序列化
位置=新位置(位置获取(0)、位置获取(1)、位置获取(2)、位置获取(3));
// ... 更多代码
我如何才能做到这一点?Java支持。请阅读“自定义默认协议”一节
引述:
然而,有一个奇怪而狡猾的解决办法。通过使用内置的
序列化机制的特性,开发人员可以增强
通过在类文件中提供两个方法来执行正常过程。
这些方法是:- 私有void writeObject(ObjectOutputStream out)抛出 IOException;
- 私有void readObject(ObjectInputStream in)抛出 IOException,ClassNotFoundException
private void writeObject(ObjectOutputStream oos)
throws IOException {
// default serialization
oos.defaultWriteObject();
// write the object
List loc = new ArrayList();
loc.add(location.x);
loc.add(location.y);
loc.add(location.z);
loc.add(location.uid);
oos.writeObject(loc);
}
private void readObject(ObjectInputStream ois)
throws ClassNotFoundException, IOException {
// default deserialization
ois.defaultReadObject();
List loc = (List)ois.readObject(); // Replace with real deserialization
location = new Location(loc.get(0), loc.get(1), loc.get(2), loc.get(3));
// ... more code
}
如果必须是Java序列化,我知道的唯一方法就是在所有类中重新定义
readObject()
和writeObject()
,这些类都引用了Location
的实例,如Momo的回答所示。请注意,这将不允许您序列化位置[]
,并要求您对代码中出现的所有集合
进行子类化。此外,它要求将Location
类型的字段标记为transient,这将排除将其定义写入序列化流的可能性,从而可能会阻止不兼容类更改的检测
更好的方法是简单地重写ObjectOutputStream.writeObject
。唉,这种方法是最终的
。您可以替代ObjectOutputStream.writeObjectOverride()
,但该方法不能委托默认实现ObjectOutputStream.writeObject0()
,因为该方法是私有的。当然,您可以使用反射调用私有方法,但是
因此,我建议验证您的约束。它必须是Java序列化吗?你真的不能改变classLocation
的定义吗
如果您有类位置
的源代码,那么添加实现可序列化
并将其添加到类路径中是非常简单的。是的,无论何时升级库,您都必须再次执行此操作,但它可能比其他方法更好…类似于@momo的答案,但不使用列表和自动装箱的int值,这将使库更加紧凑
private void writeObject(ObjectOutputStream oos) throws IOException {
// default serialization
oos.defaultWriteObject();
// write the object
oos.writeInt(location.x);
oos.writeInt(location.y);
oos.writeInt(location.z);
oos.writeInt(location.uid);
}
private void readObject(ObjectInputStream ois) throws ClassNotFoundException, IOException {
// default deserialization
ois.defaultReadObject();
location = new Location(ois.readInt(), ois.readInt(), ois.readInt(), ois.readInt());
// ... more code
}
好的,谢谢,一切都很好。但据我所知,ArrayList从未添加到writeObject
中的序列化中。我该怎么做才能正确地将列表添加到序列化中?我不认为这是真的。ArrayList实现了可序列化。重要的是ArrayList的成员也是可序列化的。您的所有成员都是int,可以在其整数(对象形式)中序列化。如果碰巧我说的不是真的,那么你可以序列化成不同的形式,比如JSON,或者如果你真的只需要四个整数,你甚至可以做一个int1,int2,int3,int4格式的字符串,并在读取过程中进行拆分。使用自定义序列化,您有许多选项来写和检索数据。不,我理解,但似乎我还需要执行oos.writeObject(loc)
我可以执行ois.readObject()
,您似乎忽略了它。哦,是的,您是对的,我错过了:)抱歉,我是在Hurry中输入的,你不必费劲地把东西包装在ArrayList
或JSON对象中。您可以只执行oos.writeInt(x);oos.writeInt(y)代码>和相应的输入方法的顺序相同。谢谢,这是一个很好的观点。然而,在我的实际代码中,我使用的不仅仅是数组,所以我使用了writeObject
。我接受了莫莫的答案,因为这是第一个答案,但在给定的情况下,这可能是一个更好的答案。请注意,最好接受最好的答案,而不是第一个正确的答案。你说彼得·劳里的答案可能更好。为了将来所有的人来到这里寻找最好的答案:请考虑接受不同的答案!