我有:
class MyClass extends MyClass2 implements Serializable { //... }
在MyClass2中是一个不可序列化的属性.如何序列化(和反序列化)此对象?
更正:MyClass2当然不是一个接口而是一个类.
正如其他人所说,Josh Bloch的Effective Java的第11章是Java序列化不可或缺的资源.
该章的几点与您的问题相关:
假设您要序列化MyClass2中非序列化字段的状态,则该字段必须可由MyClass直接访问或通过getter和setter访问.MyClass必须通过提供readObject和writeObject方法来实现自定义序列化.
非序列化字段的类必须有一个API,以允许获取它的状态(用于写入对象流),然后实例化具有该状态的新实例(稍后从对象流中读取时).
根据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只是一个接口,所以techinicaly它没有属性,只有方法.话虽这么说,如果你的实例变量本身不是可序列化的,我知道解决它的唯一方法就是声明那些字段是瞬态的.
例如:
private transient Foo foo;
声明字段瞬态时,在序列化和反序列化过程中将忽略它.请记住,当您使用瞬态字段反序列化对象时,该字段的值始终是默认值(通常为null).
请注意,您还可以覆盖类的readResolve()方法,以便根据其他系统状态初始化瞬态字段.
如果可能,可以将非可串行部件设置为瞬态
private transient SomeClass myClz;
否则你可以使用Kryo.Kryo是一个快速有效的Java对象图序列化框架(例如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不能以序列化的形式表示,那么很有可能同样的理由适用于MyClass,因为它是一个子类.
可以通过实现readObject和writeObject为MyClass编写自定义序列化表单,以便可以从序列化数据中适当地重新创建MyClass中MyClass2实例数据的状态.如果MyClass2的API已修复且您无法添加Serializable,那么这将是一种方法.
但首先你应该弄清楚为什么MyClass2不可序列化,也许可以改变它.