Java自定义序列化

n6lpvg4x  于 2023-01-24  发布在  Java
关注(0)|答案(3)|浏览(174)

我有一个对象,其中包含一些我想要序列化的不可序列化字段。它们来自一个单独的API,我无法更改它们,因此无法使它们可序列化。主要问题是Location类。它包含我需要的四个可以序列化的内容,都是int。我如何使用read/writeObject创建一个自定义序列化方法,可以执行类似以下操作:

// 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

我该怎么做呢?

wribegjk

wribegjk1#

Java支持Custom Serialization。请阅读自定义默认协议一节。
引述如下:
然而,有一个奇怪而巧妙的解决方案。通过使用序列化机制的内置特性,开发人员可以通过在类文件中提供两个方法来增强正常的过程。这些方法是:

  • 私有void写入对象(对象输出流输出)抛出IOException;
  • 私有void读取对象(对象输入流)抛出IOException,类未发现异常;

在此方法中,您可以根据需要将其序列化为其他形式,例如您所演示的Location的ArrayList、JSON或其他数据格式/方法,然后将其重新构造回readObject()
在您的示例中,添加以下代码:

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

}
dz6r00yl

dz6r00yl2#

类似于@莫莫的答案,但没有使用列表和自动装箱的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

}
mnowg1ta

mnowg1ta3#

如果必须是Java序列化,我所知道的唯一方法是在所有引用Location示例的类中重新定义readObject()writeObject(),如莫莫的答案所示。注意,这将不允许您序列化Location[],并要求您将代码中出现的所有Collection<Location>子类化。此外,它要求类型为Location的字段被标记为 transient ,这将排除它们的定义被写入串行化流,从而可能妨碍对不兼容类改变的检测。
一个更好的方法是简单地重写ObjectOutputStream.writeObject。唉,那个方法是final。你可以重写ObjectOutputStream.writeObjectOverride(),但是那个方法不能委托默认实现ObjectOutputStream.writeObject0(),因为那个方法是private。当然,你可以使用反射调用私有方法,但是...
所以我建议验证一下你的约束,一定要Java序列化吗,真的可以不修改类Location的定义吗?
如果您有Location类的源代码,那么添加implements Serializable并将其添加到您的类路径中是非常简单的。是的,无论何时升级库,您都必须再次执行此操作,但它可能比替代方法更好...

相关问题