我有:
class MyClass extends MyClass2 implements Serializable {
//...
}
在 MyClass2 中是不可序列化的属性。如何序列化(和反序列化)这个对象?
更正:MyClass2 当然不是接口而是类。
我有:
class MyClass extends MyClass2 implements Serializable {
//...
}
在 MyClass2 中是不可序列化的属性。如何序列化(和反序列化)这个对象?
更正:MyClass2 当然不是接口而是类。
正如其他人所指出的,Josh Bloch 的Effective Java第 11 章是 Java 序列化不可或缺的资源。
该章节中与您的问题相关的几点:
我在下面写了一个简单的例子来说明这一点。
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 只是一个接口,所以技术上它没有属性,只有方法。话虽如此,如果您有本身不可序列化的实例变量,我所知道的唯一解决方法是声明这些字段是瞬态的。
前任:
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,解决此问题的最简单方法是声明属性 transient。
您将需要实现writeObject()
并readObject()
手动对这些字段进行序列化/反序列化。有关详细信息,请参阅 javadoc 页面java.io.Serializable
。Josh Bloch 的Effective Java也有一些关于实现健壮和安全的序列化的好章节。
取决于为什么 MyClass2 的该成员不可序列化。
如果 MyClass2 不能以序列化形式表示是有充分理由的,那么很有可能同样的原因也适用于 MyClass,因为它是一个子类。
可以通过实现 readObject 和 writeObject 为 MyClass 编写自定义的序列化表单,这样可以从序列化数据中适当地重新创建 MyClass 中 MyClass2 实例数据的状态。如果 MyClass2 的 API 是固定的并且您不能添加 Serializable,这将是可行的方法。
但首先你应该弄清楚为什么 MyClass2 不可序列化,并可能改变它。
您可以从查看transient关键字开始,它将字段标记为不属于对象的持久状态。
出现了几种可能性,我在这里恢复它们:
XStream是一个很棒的库,可以对任何对象进行快速的 Java 到 XML 序列化,无论它是否可序列化。即使 XML 目标格式不适合您,您也可以使用源代码来学习如何操作。
序列化不可序列化类(或至少其子类)的实例的一种有用方法称为串行代理。本质上,您实现 writeReplace 以返回完全不同的可序列化类的实例,该类实现 readResolve 以返回原始对象的副本。我写了一个在Usenet上序列化 java.awt.BasicStroke 的例子