Java自定义序列化

Java自定义序列化,java,serialization,Java,Serialization,我有一个对象,其中包含一些我想要序列化的不可序列化字段。它们来自一个单独的API,我无法更改,因此使它们可序列化不是一个选项。主要问题是Location类。它包含我需要的四个可以序列化的东西,所有int。如何使用read/writeObject创建自定义序列化方法,该方法可以执行以下操作: // writeObject: List<Integer> loc = new ArrayList<Integer>(); loc.add(location.x); loc.add(l

我有一个对象,其中包含一些我想要序列化的不可序列化字段。它们来自一个单独的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
//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

在这个方法中,如果需要,可以将其序列化为其他形式,如所示位置的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

}


如果必须是Java序列化,我知道的唯一方法就是在所有类中重新定义
readObject()
writeObject()
,这些类都引用了
Location
的实例,如Momo的回答所示。请注意,这将不允许您序列化
位置[]
,并要求您对代码中出现的所有
集合
进行子类化。此外,它要求将
Location
类型的字段标记为transient,这将排除将其定义写入序列化流的可能性,从而可能会阻止不兼容类更改的检测

更好的方法是简单地重写
ObjectOutputStream.writeObject
。唉,这种方法是
最终的
。您可以替代
ObjectOutputStream.writeObjectOverride()
,但该方法不能委托默认实现
ObjectOutputStream.writeObject0()
,因为该方法是
私有的。当然,您可以使用反射调用私有方法,但是

因此,我建议验证您的约束。它必须是Java序列化吗?你真的不能改变class
Location
的定义吗


如果您有类
位置
的源代码,那么添加
实现可序列化
并将其添加到类路径中是非常简单的。是的,无论何时升级库,您都必须再次执行此操作,但它可能比其他方法更好…

类似于@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
。我接受了莫莫的答案,因为这是第一个答案,但在给定的情况下,这可能是一个更好的答案。请注意,最好接受最好的答案,而不是第一个正确的答案。你说彼得·劳里的答案可能更好。为了将来所有的人来到这里寻找最好的答案:请考虑接受不同的答案!