读书人

11.74 审慎的使用序列化

发布时间: 2013-08-25 10:49:57 作者: rapoo

11.74 谨慎的使用序列化
//序列化对象private void writeObject(String filePath,Object o){try{ObjectOutput out=new ObjectOutputStream(new FileOutputStream(new File(filePath)));out.writeObject(o);//需要与输入流的输入方法对应out.flush();out.close();}catch(Exception e){e.printStackTrace();}}//反序列化对象private Object readObject(String filePath){try{ObjectInput input=new ObjectInputStream(new FileInputStream(new File(filePath)));Object object=input.readObject(); //需要与输出流的输出方法对应input.close();return object;}catch(Exception e){e.printStackTrace();return null;}}

?

与序列化相关的方法和属性包括:

public class State implements Serializable {public static final State ON=new State(0);public static final State OFF=new State(1);private int value;private State(int value){this.value=value;}}

?

如果在代码里大量使用了State.ON、State.OFF,那么在反序列化时会创建大量的State对象(默认情况下反序列化将创建一个新的对象),可以使用如下代码避免此问题:

public class State implements Serializable {public static final State ON=new State(0);public static final State OFF=new State(1);private int value;private State(int value){this.value=value;} private Object writeReplace() throws ObjectStreamException{ return value==ON.value?ON:OFF;//序列化同一个对象 }  private Object readResolve() throws ObjectStreamException{ return value==ON.value?ON:OFF;//反序列化同一个对象 }}

?

另一种方法是使用序列化代理类(类似flyweight设计模式),如下:

public class State implements Serializable {public static final State ON=new State(0);public static final State OFF=new State(1);private int value;private State(int value){this.value=value;}          //使用StateProxy作为序列化对象。State不需要覆盖readResolve() private Object writeReplace() throws ObjectStreamException{ return value==ON.value?StateProxy.ON:StateProxy.OFF; }   //序列化代理类 private static final class StateProxy implements Serializable{ final static StateProxy ON=new StateProxy(State.ON.value); final static StateProxy OFF=new StateProxy(State.OFF.value);  private int value;  private StateProxy(int value){ this.value=value; }                                  //返回反序列的被代理的State对象 private Object readResolve() throws ObjectStreamException{ return value==ON.value?State.ON:State.OFF; }  } }

?

以下为测试代码:

@Testpublic void testStateSerial(){writeObject("./state.ser", State.OFF);State state=(State)readObject("./state.ser");Assert.assertSame(state, State.OFF);}

注:如果序列化类是类似State的简单的类,最好的方式是使用枚举类。同一个枚举量反序列化后返回同一个对象。所以也可以使用枚举类实现单例模式

?

如果子类实现了Serializable接口,但是父类没有实现。那么JVM不会序列化父类对象,但是序列化子类对象时必须调用父类的构造函数,所以此情况父类必须提供无参的构造函数。

?

Apache Commons提供了序列化工具类 ,具体请参考官方帮助文档

?

其它需要注意的地方:

1.修改可序列化类的结构,可能导致已经序列化的对象在反序列化时失败(可重新加载最新的class文件后再进行反序列化 )

?

2.反序列化可能引入安全问题

?

3.序列化增加测试工作(原因见第1条)

?

4.建议仅有值对象的类(如Date,BigInteger)提供序列化功能

?

5.接口和用于继承的父类,内部类应尽量不要实现Serializable接口

?

读书人网 >编程

热点推荐