Java自定义序列化
我有一个对象,其中包含我想序列化一些不可序列化的字段。 他们来自一个单独的API,我不能改变,所以使他们可序列化是不是一个选项。 主要的问题是Location类。 它包含四个我可以序列化的东西,所有的整数。 我如何使用read / writeObject来创build一个自定义的序列化方法,可以这样做:
// 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
我该怎么做?
Java支持自定义序列化 。 阅读“自定义默认协议”一节。
去引用:
然而,有一个奇怪而又狡猾的解决scheme。 通过使用序列化机制的内置function,开发人员可以通过在其类文件中提供两种方法来增强正常进程。 这些方法是:
- private void writeObject(ObjectOutputStream out)throws IOException;
- private void readObject(ObjectInputStream in)throws IOException,ClassNotFoundException;
在这种方法中,如果需要的话,可以将其序列化为其他forms,比如说明的位置的ArrayList或JSON或其他数据格式/方法,并在readObject()上重新构build它
用你的例子,你添加下面的代码:
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 }
类似于@ momo的答案,但不使用List和自动装箱的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 }
如果它必须是Java序列化,那么我所知道的唯一方法是重新定义所有具有对Location
实例的引用的类中的readObject()
和writeObject()
,如Momo的答案中所示。 请注意,这将不允许您序列化一个Location[]
,并要求您inheritance代码中出现的所有Collection<Location>
。 此外,它要求typesLocation
的字段被标记为瞬态的,这将排除它们的定义被写入序列化stream,可能会导致检测到不兼容的类变化。
更好的方法是简单地覆盖ObjectOutputStream.writeObject
。 唉,那个方法是final
。 您可以重写ObjectOutputStream.writeObjectOverride()
,但该方法不能委托默认实现ObjectOutputStream.writeObject0()
因为该方法是private
。 当然,你可以使用reflection来调用私有方法,但是…
因此,我build议您validation您的约束。 它是否必须是Java序列化? 你真的不能改变类Location
的定义吗?
如果你有类Location
的源代码,添加implements Serializable
并将其添加到你的类path是相当简单的。 是的,每当你升级图书馆时,你都必须重新这样做,但它可能比另一种更好。