《Effective Java》一书中提到的序列化代理模式,是一种有效处理类序列化难题的方法。假设你正在设计一个继承体系,其中基类并不支持序列化,且没有无参构造器,如以下示例:
public class BasePoint { private String label; private double x; private double y; protected BasePoint(double x, double y, String label) { this.x = x; this.y = y; this.label = label; } public String getLabel() { return label; } public double getX() { return x; } public double getY() { return y; } ... }
当你试图扩展这个基类,创建一个新的子类并实现序列化功能时,例如:
public class ExtendedPoint extends BasePoint implements Serializable { public ExtendedPoint(double x, double y, String label) { super(x, y, label); } ... }
尝试序列化和反序列化ExtendedPoint
实例时,会遇到InvalidClassException
异常,提示没有合适的构造器。这时,序列化代理模式就能派上用场了。
首先,在ExtendedPoint
类中添加一个静态内部类作为序列化代理:
private static class SerializationHelper implements Serializable { private String label; private double x; private double y; public SerializationHelper(ExtendedPoint point) { this.label = point.getLabel(); this.x = point.getX(); this.y = point.getY(); } private Object readResolve() { return new ExtendedPoint(x, y, label); } }
接下来,还需要在ExtendedPoint
类中定义一个方法来指定序列化时使用的代理对象:
private Object writeReplace() { return new SerializationHelper(this); }
这样,当ExtendedPoint
对象被序列化时,实际被序列化的将是SerializationHelper
对象。而在反序列化过程中,readResolve
方法会被调用,返回一个新的ExtendedPoint
实例。
通过这种方式,即使基类不具备序列化能力或标准构造器,也能成功实现子类的序列化。此外,为了保护类的不变性,还可以禁止直接反序列化ExtendedPoint
对象:
private void readObject(ObjectInputStream stream) throws InvalidObjectException { throw new InvalidObjectException("Use Serialization Proxy instead."); }
这确保了只有通过序列化代理才能正确恢复对象的状态,从而维护了类的设计完整性。