1、什么是序列化和反序列化
对象的寿命通常随着生成该对象的程序的终止而终止,有时候,可能需要将对象的状态保存下来,在需要时再将对象恢复。我们把对象的这种,能记录自己的状态以便将来再生的能力,叫作对象的持续性(persistence)。
对象通过写出描述自己状态的数值来记录自己 ,这个过程叫对象的序列化或串行化(Serialization) 。序列化的主要任务是记录对象实例变量的数值,如果变量是另一对象的引用,则引用的对象也要序列化,这个过程是递归的。
序列化可能要涉及一个复杂树结构的单行化,包括原有对象、对象的对象、对象的对象的对象等等。
对象所有权的层次结构称为图表(graph)。
简单说,Serialization是一种将【对象】以一连串的字节进行描述的过程,而反序列化是一种将这些字节重建成一个对象的过程。
2、什么情况下需要序列化
- 当你想把的【内存】中的对象保存到一个文件中或者数据库中时候;
- 当你想用套接字在网络上【传送】对象的时候;
- 当你想通过RMI【传输】对象的时候;
另一种描述:
- 作为一种持久化机制 如果使用的是FileOutputStream流的方式,则数据将被自动地写入文件中,
- 作为一种复制机制 如果使用的是ByteArrayOutputStream流的方式,数据将写入内存中的字节数组中。该字节数组可以用来创建初始对象的副本,
- 作为一种通信机制 如果是使用套接字(Socket)流的方式,则数据自动地通过网络连接传输一另一个端点,并由这个端点上的程序来决定做什么。
3、如何实现序列化、反序列化
将需要序列化的类实现Serializable接口就可以了,Serializable接口中没有任何方法,可以理解为一个标记,即表明这个类可以序列化。
如果我们想要序列化一个对象,首先要创建字节输出流OutputStream(如FileOutputStream、ByteArrayOutputStream等),并将这些OutputStream封装在一个【ObjectOutputStream】中。然后只需调用其writeObject()方法就可以将对象序列化,并将其发送给OutputStream。
如果我们想要反序列化为一个对象,需要将一个InputStream(如FileInputstream、ByteArrayInputStream等)封装在【ObjectInputStream】内,然后调用其readObject()即可。
4、序列化的serialVersionUID
序列化 ID 在 Eclipse 下提供了两种生成策略,一个是固定的 long 类型的1L,一个是随机生成一个不重复的 long 类型数据(实际上是使用 JDK 工具生成)。
在这里有一个建议,如果没有特殊需求,就是用默认的 1L 就可以,这样可以确保代码一致时反序列化成功,因为不同的序列化id之间不能进行序列化和反序列化,这也可能是造成序列化和反序列化失败的原因。
5、序列化前后,对象的关系
反序列化还原生成的对象与原来的对象的地址不同,但是内容是一样的,而且对象中包含的引用也相同。
换句话说,通过序列化操作,我们可以实现对任何可Serializable对象的【深度复制】——这意味着我们复制的是整个对象网,而不仅仅是基本对象及其引用。
对于同一流的对象,他们的地址是相同,说明他们是同一个对象,但是与其他流的对象地址却不相同。
也就说,只要将对象序列化到单一流中,就可以恢复出与我们写出时一样的对象网,而且只要在同一流中,对象都是同一个。
6、静态变量能否序列化
静态成员属于类级别的,所以不能序列化,即序列化的是对象的状态不是类的状态。
这里的不能序列化的意思,是序列化信息中不包含这个静态成员域。
7、总结
- a)当一个父类实现序列化,子类自动实现序列化,不需要显式实现Serializable接口;
- b)当一个对象的实例变量引用其他对象,序列化该对象时也把引用对象进行序列化(引用对象也要实现Serializable接口);
- c)static,transient后的变量不能被序列化;