effective java(序列化)

来源:互联网 发布:网络龙虎游戏 编辑:程序博客网 时间:2024/06/05 08:25

1、谨慎地实现Serializable接口

a、实现Serializable接口而付出的代价是,一旦一个类被发布,就大大降低了“改变这个类的实现”的灵活性

系列化会使类的演变受到限制,这种限制与流的唯一标示符有关,通常也称做序列版本UID。如果你没有显示的声明序列版本,系统就会自动地根据这个类来调用一个复杂的元素过程,从而在运行时产生标识号(这个值首类名、实现的接口名称、以及所有公有的和受保护的成员的名称所影响)。

b、实现Serializable接口的第二个代价是,它增加了出现Bug和安全漏洞的可能性。

系列化机制是一种语言之外的对象创建机制。

c、实现Serializable接口的第三个代价是,随着发行新的版本,相关测试负担也增加了。

很重要的一点:要检查是否可以“在新版本中序列化一个实例,然后在旧版本中反序列化”,反之亦然。

根据经验:如Date和BigInteger这样的值类应该实现Serializable接口,大多数集合类也该如此。代表活动实体的类,如线程池,一般不应该实现Serializable。

2、考虑使用自定义的序列化形式

public final class StringList implements Serializable {

private transient int size = 0;

private transient Entry head;

private final class Entry implements Serializable {

//  默认的序列化形式会镜像出列表中的所有项,以及这些项之间的所有双相链接。

String data;

Entry next;

Entry previous;

}

public final void add(String s){}

private void writeObject(ObjectOutputStream s){

s.defaultWriteObject();

s.writeInt(size);

for(Entry e = head; e != null; e = e.next){

s.writeObject(e);

}

}

private void readObject(ObjectInputSream s){

s.defaultReadObject();

int numElements = s.readInt();

for (int i = 0; i < numElements; i++) {
add((String)s.readObject());

}

}

}

无论你是否使用默认的序列化形式,如果在读取整个对象状态的任何其他方法上强制任何同步,则也必须在对象序列化上强制这种同步。

3、保护性地编写readObject方法

4、对于实例控制,枚举类型优先于readResolve

readResolve特性允许你用readObject创建的实例代替另一个实例。对于一个正在被反序列化的对象,如果它的类定义了readResolve方法,并且具备正确的声明,那么在反序列化之后,新建对象上的readResolve方法将被调用。然后,该方法返回的对象引用将被返回,取代新建的对象。

5、考虑用序列化代理代替序列化实例

为可序列化的类设计一个私有的静态嵌套类,精确地表示外围类的实例的逻辑状态。这个嵌套类被称做序列化代理,它应该有一个单独的构造器,其参数就是那个外围类。这个构造器从它的参数中复制数据:它不需要进行任何一致性检查和保护性拷贝。从设计角度看,序列化代理的默认序列化形式是外围类最爱好的序列化形式。外围类及其序列代理都必须声明实现Serializable接口。




原创粉丝点击