- 如果使用序列化来保存对象,就需要考虑在程序演化时会出现的问题。例如,新版本可以读入旧文件吗?旧版本可以读入新版本产生的文件吗?
- 乍一看,这好像是不能的。无论类的定义产生了什么样的变化,它的
SHA
指纹也跟着变化,而我们都知道对象输入流将拒绝读入具有不同指纹的对象。但是,类可以表明它对早期版本保持兼容,要想这样做,就必须首先获得这个类的早期版本指纹。这个类的所有较新的版本都必须把serialVersionUID
常量定义为与最初版本的指纹相同。
public static final long serialVersionUID = -5731003754099293592L;
- 如果一个类具有名为
serialVersionUID
的静态数据成员,他就不再需要人工地计算其指纹,而只需直接使用这个值。 - 一旦这个静态数据成员被置于某个类的内部,那么序列化系统就可以读入这个类的对象的不同版本。
- 如果这个类只有方法发生了变化,那么在读入新对象数据时是不会有任何问题的。但是,如果数据域产生了变化,那么就可能会有问题。例如,旧文件对象可能比程序中的对象有更多或更少的数据域,或者数据域的类型可能有所不同。在这些情况中,对象输入流将尽力将流都对象转换成这个类的当前版本。
- 对象输入流会将这个类当前版本的数据域与被序列化的版本中的数据域进行比较,当然,对象流只会考虑非瞬时和非静态的数据域。如果这两部分数据域之间名字匹配而类型不匹配,那么对象不会尝试将一种类型转换成另一种类型,因为这两个对象不兼容;如果被序列化的对象具有在当前版本中所没有的数据域,那么对象输入流会忽略这些额外的数据;如果当前版本具有在当前版本中所没有的数据域,那么这些新添加的域将被设置成它们的默认值(如果是对象则是
null
,如果是数字则为0
,如果是boolean
值则是false
)
![读入具有较少数据域的对象](https://i-blog.csdnimg.cn/blog_migrate/f2f8e914c84a15c926e7d0ee2df29d2c.jpeg)
![读入具有较多数据域的对象](https://i-blog.csdnimg.cn/blog_migrate/ebce15f7acfdd15f61ac242091193c52.jpeg)