我有:
class MyClass extends MyClass2 implements Serializable {
//...
}
在MyClass2中是一个不可序列化的属性。如何序列化(和反序列化)此对象?
更正:MyClass2当然不是一个接口而是一个类。
答案 0 :(得分:49)
正如其他人所说,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;
}
}
答案 1 :(得分:35)
MyClass2只是一个界面,所以techinicaly它没有属性,只有方法。如果你有实例变量本身不是可序列化的,那么我所知道的唯一方法就是将这些字段声明为瞬态。
例如:
private transient Foo foo;
声明字段瞬态时,在序列化和反序列化过程中将忽略它。请记住,当您使用瞬态字段反序列化对象时,该字段的值始终是默认值(通常为空。)
注意,您也可以覆盖类的readResolve()方法,以便根据其他系统状态初始化瞬态字段。
答案 2 :(得分:15)
如果可能,可以将非可串行部件设置为瞬态
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)));
答案 3 :(得分:11)
如果您可以修改MyClass2,解决此问题的最简单方法是声明属性瞬态。
答案 4 :(得分:6)
您需要实现writeObject()
和readObject()
并对这些字段进行手动序列化/反序列化。有关详细信息,请参阅java.io.Serializable
的javadoc页面。 Josh Bloch的 Effective Java 在实现健壮和安全的序列化方面也有一些很好的章节。
答案 5 :(得分:5)
取决于为什么MyClass2的成员不可序列化。
如果有一个很好的理由说明为什么MyClass2不能以序列化的形式表示,那么很有可能同样的理由适用于MyClass,因为它是一个子类。
可以通过实现readObject和writeObject为MyClass编写自定义序列化表单,以便可以从序列化数据中适当地重新创建MyClass中MyClass2实例数据的状态。如果MyClass2的API已修复且您无法添加Serializable,那么这将是一种方法。
但首先你要弄清楚为什么MyClass2不可序列化,也许可以改变它。
答案 6 :(得分:4)
您可以从查看 transient 关键字开始,该关键字将字段标记为不属于对象持久状态的一部分。
答案 7 :(得分:4)
有几种可能性,我在这里恢复它们:
答案 8 :(得分:3)
XStream是一个很棒的库,可以为任何对象执行快速Java到XML序列化,无论它是否可序列化。即使XML目标格式不适合您,也可以使用源代码来学习如何操作。
答案 9 :(得分:2)