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是相当简单的。 是的,每当你升级图书馆时,你都必须重新这样做,但它可能比另一种更好。