1、当你想把的内存中的对象状态保存到一个文件中或者数据库中时候;
2、当你想用套接字在网络上传送对象的时候;
java对象序列化不仅保留一个对象的数据,而且递归保存对象引用的每个对象的数据。可以将整个对象层次写入字节流中,可以保存在文件中或在网络连接上传递。利用对象序列化可以进行对象的"深复制",即复制对象本身及引用的对象本身。序列化一个对象可能得到整个对象序列。
3、当你想通过RMI传输对象的时候;
RMI要利用对象序列化运行远程主机上的服务,就像在本地机上运行对象时一样。
(1).当一个对象被序列化时,只保存对象的非静态成员变量,不能保存任何的成员方法,静态的成员变量和transient标注的成员变量。
序列化的核心问题
1.默认序列化方式
如果仅仅只是让某个类实现Serializable接口,而没有其它任何处理的话,则就是使用默认序列化机制。使用默认机制,在序列化对象时,不仅会序列化当前对象本身,还会对该对象引用的其它对象也进行序列化【引用的类也要实现接口】,同样地,这些其它对象引用的另外对象也将被序列化,以此类推。所以,如果一个对象包含的成员变量是容器类对象,而这些容器所含有的元素也是容器类对象,那么这个序列化的过程就会较复杂,开销也较大。
2.版本问题
3.自定义默认序列化
【隐藏某些字段】
某个字段被声明为transient后,默认序列化机制就会忽略该字段。此处将Person类中的age字段声明为transient,如下所示,
- public class Person implements Serializable {
- ...
- transient private Integer age = null;
- ...
- }
再执行SimpleSerial应用程序,会有如下输出:
- arg constructor
- [John, null, MALE]
可见,age字段未被序列化。
【writeObject()方法与readObject()方法】
对于上述已被声明为transitive的字段age,除了将transitive关键字去掉之外,是否还有其它方法能使它再次可被序列化?方法之一就是在Person类中添加两个方法:writeObject()与readObject(),如下所示:
- public class Person implements Serializable {
- ...
- transient private Integer age = null;
- ...
- private void writeObject(ObjectOutputStream out) throws IOException {
- out.defaultWriteObject();
- out.writeInt(age);
- }
- private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
- in.defaultReadObject();
- age = in.readInt();
- }
- }
在writeObject()方法中会先调用ObjectOutputStream中的defaultWriteObject()方法,该方法会执行默认的序列化机制,如5.1节所述,此时会忽略掉age字段。然后再调用writeInt()方法显示地将age字段写入到ObjectOutputStream中。readObject()的作用则是针对对象的读取,其原理与writeObject()方法相同。再次执行SimpleSerial应用程序,则又会有如下输出:
- arg constructor
- [John, 31, MALE]
必须注意地是,writeObject()与readObject()都是private方法,那么它们是如何被调用的呢?毫无疑问,是使用反射。详情可以看看ObjectOutputStream中的writeSerialData方法,以及ObjectInputStream中的readSerialData方法
4.对象引用的序列化