是否可以使用Serializable接口进行选择性序列化?



假设我的类MyClass有10个变量。通过用Serializable标记类,我们序列化了所有10个变量。

我的问题是有没有办法只序列化其中的一些变量,比如只序列化5个?

我知道可以通过将变量标记为transient来完成。但是我想知道是否有任何其他的方法来做到这一点,而不是使用transient关键字。

如果您的类实现了Externalizable接口,那么您将更好地控制对象的序列化方式。

请注意,与Serializable不同,Externalizable接口不是一个标记接口,您需要实现readExternal()writeExternal()方法,在这些方法中,您实际上可以以编程方式选择要序列化的类成员以及如何进行反序列化。

更多信息:

  • SerializableExternalizable的差异

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对象。

该技术的优点是可以将序列化形式与内部表示完全分离,允许您任意更改内部表示,只要它可以从序列化形式重新构建。

最新更新