Java序列化与不可序列化的部分

我有:

class MyClass extends MyClass2 implements Serializable { //... } 

在MyClass2中是一个不可序列化的属性。 我如何序列化(和反序列化)这个对象?

更正:MyClass2当然不是一个接口,而是一个类。

正如其他人所指出的,Josh Bloch的Effective Java第11章是Java序列化不可或缺的资源。

有关你的问题的那一章有几点:

  • 假设您想序列化MyClass2中的不可序列化字段的状态,那么该字段必须可以直接或通过getter和setter访问MyClass。 MyClass将不得不通过提供readObject和writeObject方法来实现自定义序列化。
  • 非序列化字段的类必须有一个API来允许获取它的状态(用于写入对象stream),然后用该状态实例化一个新实例(当从对象stream中读取时)。
  • 根据Effective Java的第74项,MyClass2 必须有一个无参数构造函数可以被MyClass访问,否则MyClass不可能扩展MyClass2并实现Serializable。

我在下面写了一个快速示例来说明这一点。

 class MyClass extends MyClass2 implements Serializable{ public MyClass(int quantity) { setNonSerializableProperty(new NonSerializableClass(quantity)); } private void writeObject(java.io.ObjectOutputStream out) throws IOException{ // note, here we don't need out.defaultWriteObject(); because // MyClass has no other state to serialize out.writeInt(super.getNonSerializableProperty().getQuantity()); } private void readObject(java.io.ObjectInputStream in) throws IOException { // note, here we don't need in.defaultReadObject(); // because MyClass has no other state to deserialize super.setNonSerializableProperty(new NonSerializableClass(in.readInt())); } } /* this class must have no-arg constructor accessible to MyClass */ class MyClass2 { /* this property must be gettable/settable by MyClass. It cannot be final, therefore. */ private NonSerializableClass nonSerializableProperty; public void setNonSerializableProperty(NonSerializableClass nonSerializableProperty) { this.nonSerializableProperty = nonSerializableProperty; } public NonSerializableClass getNonSerializableProperty() { return nonSerializableProperty; } } class NonSerializableClass{ private final int quantity; public NonSerializableClass(int quantity){ this.quantity = quantity; } public int getQuantity() { return quantity; } } 

MyClass2只是一个界面,所以技术上它没有属性,只有方法。 这就是说,如果你有本身不可序列化的实例variables,我知道解决这个问题的唯一方法就是声明这些字段是瞬态的。

例如:

 private transient Foo foo; 

当你声明一个场瞬态时,在序列化和反序列化过程中将被忽略。 请记住,当您使用瞬态字段反序列化对象时,该字段的值将始终为默认值(通常为null)。

注意你也可以重载你的类的readResolve()方法来初始化基于其他系统状态的瞬态字段。

如果可能,不可串行的部分可以设置为瞬态

 private transient SomeClass myClz; 

否则,你可以使用Kryo 。 Kryo是一个快速和高效的Java对象graphics序列化框架(例如java.awt.Color的JAVA序列化需要170字节,Kryo只有4个字节),它也可以序列化不可序列化的对象。 Kryo也可以执行自动深层和浅层复制/克隆。 这是直接从对象拷贝到对象,而不是object->bytes->object

这里是一个如何使用kryo的例子

 Kryo kryo = new Kryo(); // #### Store to disk... Output output = new Output(new FileOutputStream("file.bin")); SomeClass someObject = ... kryo.writeObject(output, someObject); output.close(); // ### Restore from disk... Input input = new Input(new FileInputStream("file.bin")); SomeClass someObject = kryo.readObject(input, SomeClass.class); input.close(); 

序列化对象也可以通过注册确切的序列化器进行压缩:

 kryo.register(SomeObject.class, new DeflateCompressor(new FieldSerializer(kryo, SomeObject.class))); 

如果你可以修改MyClass2,解决这个问题最简单的方法是声明属性瞬态。

您需要实现writeObject()readObject() ,并对这些字段进行手动序列化/反序列化。 有关详细信息,请参阅java.io.Serializable的javadoc页面。 Josh Bloch的Effective Java在实现健壮和安全的序列化方面也有一些很好的章节。

取决于MyClass2的成员不可序列化的原因。

如果说MyClass2不能以序列化的forms表示出来,那么很可能是同样的原因适用于MyClass,因为它是一个子类。

通过实现readObject和writeObject,可以为MyClass编写一个自定义的序列化表单,以便MyClass中的MyClass2实例数据的状态可以从序列化的数据中适当地重新创build。 这将是如果MyClass2的API是固定的,你不能添加Serializable的路要走。

但首先你应该弄清楚为什么MyClass2不可序列化,也许可以改变它。

您可以从查看transient关键字开始,该关键字将字段标记为不是对象持久状态的一部分。

几种可能性,我恢复他们在这里:

  • 像skbuild议的那样实现writeObject()和readObject()
  • 声明属性transient,并且不会像hank所声明的那样序列化
  • 按照boris-terzic的说法使用XStream
  • 使用tom-hawtin-tackline所述的串行代理

XStream是一个伟大的库,可以为任何对象执行快速的Java到XML序列化,而不pipe它是否是可序列化的。 即使XML目标格式不适合你,你也可以使用源代码来学习如何做到这一点。

串行化不可序列化类(或至less其子类)的实例的有用方法是已知的串行代理。 基本上你实现writeReplace来返回一个完全不同的可序列化的类的实例,它实现了readResolve来返回原始对象的副本。 我写了一个在Usenet上序列化java.awt.BasicStroke的例子