一、采用Serializable方式进行对象的序列化和反序列化,反序列化成功后得到的对象和序列化时的对象内容完全一样,但是两者并不是同一个对象。
二、serialVersionUID是用来辅助序列化和反序列化过程的,原则上序列化化后的数据中的serialVersionUID只有和当前类的serialVersionUID相同才能够正常地被反序列化。
serialVersionUID的详细工作机制是这样的:序列化的时候系统会把当前类的serialVersionUID写入序列化的文件中(也可能是其他中介),当反序列化的时候系统会去检测文件中的serialVersionUID,看它是否和当前类的serialVersionUID一致,如果一致就说明序列化的类的版本和当前类的版本是相同的,这个时候可以反序列化成功;否者就说明当前类和序列化的类相比发生了某些变换,比如成员变量的数量、类型可能发生了改变,这个时候是无法正常反序列化的。
三、一般来说,我们应该手动指定serialVersionUID的值,比如1L,也可以让Eclipse根据当前类的结构自动去生成它的hash值,这样序列化和反序列化时两者的serialVersionUID是相同的,因此可以正常进行反序列化。如果不动手指定serialVersionUID的值,反序列化时,当前类有所改变,比如增加或者删除了某些成员变量,那么系统就会重新计算当前类的hash值并把它赋值给serialVersionUID,这个时候当前类的serialVersionUID就和序列化的数据中的serialVersionUID不一致,于是反序列化失败,程序就会出现crash。
所以,手动指定serialVersionUID后就可以在很大程度上避免反序列化过程的失败。比如当版本升级后,我们可能删除了某个成员变量也可能怎讲了一些新的成员变量,这个时候我们的反序列化过程仍能够成功,程序仍然能够最大限度地恢复数据,相反,如果不指定serialVersionUID的话,程序会挂掉。
当然,如果类结构发生了非常规性改变,比如修改了类名,修改了成员变量的烈性,这个时候尽管serilaVersionUID验证通过,但是反序列化过程还是会失败,因为类结构有了毁灭性的改变,根本无法从老版本的数据中还原一个新的类结构的对象。
四、需要注意以下两点
首先静态成员变量属于类不属于对象,所以不会参与序列化过程;其次,用transient关键字标记的成员变量不参与序列化过程。
另外,系统的默认序列化过程也是可以改变的,通过实现writeObject(ObjectOutputStream out)和readObject(ObjectInputStream in)两个方法即可重写系统默认的序列化和反序列化过程。
摘自《Android开发艺术探索》
网友评论