假设我的类MyClass
有10个变量。通过用Serializable
标记类,我们序列化了所有10个变量。
我的问题是有没有办法只序列化其中的一些变量,比如只序列化5个?
我知道可以通过将变量标记为transient
来完成。但是我想知道是否有任何其他的方法来做到这一点,而不是使用transient
关键字。
如果您的类实现了Externalizable
接口,那么您将更好地控制对象的序列化方式。
请注意,与Serializable
不同,Externalizable
接口不是一个标记接口,您需要实现readExternal()
和writeExternal()
方法,在这些方法中,您实际上可以以编程方式选择要序列化的类成员以及如何进行反序列化。
更多信息:
-
Serializable
与Externalizable
的差异
Java支持自定义序列化。阅读自定义默认协议一节。
然而,有一个奇怪而巧妙的解决方案。通过使用内置的特性的序列化机制,开发人员可以增强通过在类文件中提供两个方法来实现正常进程。这些方法是:private void writeObject(ObjectOutputStream out)抛出IOException;
private void readObject(ObjectInputStream in)抛出IOException,ClassNotFoundException。
当您想要自定义序列化时,一个选项是使用序列化代理:而不是您的"真实"对象,而是创建一个被序列化的替代品。序列化框架使用writeReplace()/readResolve()
方法,它允许您执行此操作。
大致是这样的:
public class Foo implements Serializable {
private final String bar;
private final String baz;
private static class FooProxy implements Serializable {
private final String barBaz;
private FooProxy(Foo foo) {
this.barBaz = foo.bar + "|" + foo.baz; //don't do this for real
}
private Object readResolve() {
String [] arr = this.barBaz.split( "|" );
return new Foo(arr[0], arr[1]);
}
}
private Object writeReplace() {
return new FooProxy(this);
}
// this method is required to stop a maliciously constructed serialized form to be deserialized
private void readObject(ObjectInputStream ois) throws InvalidObjectException {
throw new InvalidObjectException( "Use a proxy." );
}
}
因此,每次序列化Foo
时,它都被替换为具有完全不同字段的FooProxy
对象,而每次反序列化FooProxy
时,它都被替换为相应的Foo
对象。
该技术的优点是可以将序列化形式与内部表示完全分离,允许您任意更改内部表示,只要它可以从序列化形式重新构建。