对象序列化
程序在运行过程中,可能需要将一些数据永久的保存到磁盘上,而数据在Java中都是保存在对象当中的。那么我们要怎样将对象中的数据保存到磁盘上呢?这时就需要使用Java中的对象序列化。
对象的序列化(Serializable)是指将一个Java对象转换成一个I/O流中字节序列的过程。其目的是为了将对象保存到磁盘中,或允许在网络中直接传输对象。对象序列化机制可以使内存中的Java对象转换成与平台无关的二进制流,既可以将这种二进制流持久地保存在磁盘上,又可以通过网络将这种二进制流传输到另一个网络节点,其他程序在获得了这种二进制流后,还可以将它恢复成原来的Java对象。这种将I/O流中的字节序列恢复为Java对象的过程被称之为反序列化(Deserialize)。
如果想让某个对象支持序列化机制,那么这个对象所在的类必须是可序列化的。在Java中,可序列化的类必须实现Serializable或Externalizable两个接口之一。这两个接口实现序列化机制的主要区别如表1所示。
表1 实现Serializable与实现Externalizable的对比
实现Serializable**接口** | 实现Externalizable**接口** |
---|---|
系统自动存储必要的信息 | 由程序员决定所存储的信息 |
Java内部支持,易于实现,只需实现该接口即可,不需要其他代码支持 | 接口中只提供了两个空方法,实现该接口必须为两个空方法提供实现 |
性能较差 | 性能较好 |
与实现Serializable接口相比,虽然实现Externalizable接口可以带来一定性能上的提升,但也将导致编程的复杂度增加。在实际开发时,大部分都是采用实现Serializable接口的方式来实现序列化的。
使用Serializable接口实现序列化非常简单,只需要让目标类实现Serializable接口即可,无需实现任何方法。例如让Person类实现序列化接口的代码如下:
public class Person implements Serializable{
// 为该类指定一个serialVersionUID变量值
private static final long serialVersionUID = 1L;
//声明变量
private int id;
private String name;
private int age;
// 此处省略各属性的getter和setter方法
...
}
在上述代码中,Person类实现了Serializable接口,并指定了一个serialVersionUID变量值,该变量值的作用是标识Java类的序列化版本。如果不显示的定义serialVersionUID变量值,那么将由JVM根据类的相关信息计算出一个serialVersionUID变量值。
小提示:
serialVersionUID适用于Java的序列化机制。简单来说,Java的序列化机制是通过判断类的serialVersionUID来验证版本一致性的。在进行反序列化时,JVM会把传来的字节流中的serialVersionUID与本地相应实体类的serialVersionUID进行比较,如果相同就认为是一致的,可以进行反序列化,否则就会出现序列化版本不一致的异常。因此,为了在反序列化时确保序列化版本的兼容性,最好在每一个要序列化的类中加入private static final long serialVersionUID的变量值,具体数值可自定义(默认是1L,系统还可以根据类名、接口名、成员方法及属性等生成的一个64位的哈希字段)。这样,某个对象被序列化之后,即使它所对应的类被修改了,该对象也依然可以被正确的反序列化。