序列化与反序列化

来源:互联网 发布:专门下软件的网站 编辑:程序博客网 时间:2024/06/06 04:19

序列化与反序列

        Serialization(序列化)是一种将对象以一连串的字节描述的过程;反序列化deserialization是一种将这些字节重建成一个对象的过程。Java序列化是指把Java对象转换为字节序列的过程;而Java反序列化是指把字节序列恢复为Java对象的过程。
把对象转换为字节序列的过程称为对象的序列化。
把字节序列恢复为对象的过程称为对象的反序列化。
对象的序列化主要有两种用途:
  1、 把对象的字节序列永久地保存到硬盘上,通常存放在一个文件中;
  2、 在网络上传送对象的字节序列。
  在很多应用中,需要对某些对象进行序列化,让它们离开内存空间,入住物理硬盘,以便长期保存。比如最常见的是Web服务器中的Session对象,当有 10万用户并发访问,就有可能出现10万个Session对象,内存可能吃不消,于是Web容器就会把一些seesion先序列化到硬盘中,等要用了,再把保存在硬盘中的对象还原到内存中。
  当两个进程在进行远程通信时,彼此可以发送各种类型的数据。无论是何种类型的数据,都会以二进制序列的形式在网络上传送。发送方需要把这个Java对象转换为字节序列,才能在网络上传送;接收方则需要把字节序列再恢复为Java对象。

序列化的需求场景

1、需要把内存中的对象保存到一个文件中或者数据库中时候;
2、需要用套接字在网络上传送对象的时候;
3、需要通过RMI传输对象的时候;

如何实现序列化

        将需要序列化的类实现Serializable接口就可以了,Serializable接口中没有任何方法,可以理解为一个标记,即表明这个类可以序列化。
1、JDK类库中序列化API
      java.io.ObjectOutputStream:表示对象输出流
     它的writeObject(Object obj)方法可以对参数指定的obj对象进行序列化,把得到的字节序列写到一个目标输出流中。
      java.io.ObjectInputStream:表示对象输入流
     它的readObject()方法源输入流中读取字节序列,再把它们反序列化成为一个对象,并将其返回。
(记住:对象的序列化是基于字节的,不能使用Reader和Writer等基于字符的层次结构)
2、实现序列化的要求
      只有实现了Serializable或Externalizable接口的类的对象才能被序列化,否则抛出异常。
Externalizable接口继承自 Serializable接口,实现Externalizable接口的类完全由自身来控制序列化的行为,而仅实现Serializable接口的类可以采用默认的序列化方式。
3、实现Java对象序列化与反序列化的方法
假定一个Student类,它的对象需要序列化,可以有如下三种方法:
方法一:若Student类仅仅实现了Serializable接口,则可以按照以下方式进行序列化和反序列化ObjectOutputStream采用默认的序列化方式,对Student对象的非transient的实例变量进行序列化。
ObjcetInputStream采用默认的反序列化方式,对对Student对象的非transient的实例变量进行反序列化。
方法二:若Student类仅仅实现了Serializable接口,并且还定义了readObject(ObjectInputStream in)和writeObject(ObjectOutputSteam out),则采用以下方式进行序列化与反序列化。
ObjectOutputStream调用Student对象的writeObject(ObjectOutputStream out)的方法进行序列化。
ObjectInputStream会调用Student对象的readObject(ObjectInputStream in)的方法进行反序列化。
方法三:若Student类实现了Externalnalizable接口,且Student类必须实现readExternal(ObjectInput in)和writeExternal(ObjectOutput out)方法,则按照以下方式进行序列化与反序列化。
ObjectOutputStream调用Student对象的writeExternal(ObjectOutput out))的方法进行序列化。
ObjectInputStream会调用Student对象的readExternal(ObjectInput in)的方法进行反序列化。

序列化ID

       序列化 ID 在 Eclipse 下提供了两种生成策略,一个是固定的 1L,一个是随机生成一个不重复的 long 类型数据(实际上是使用 JDK 工具生成),在这里有一个建议,如果没有特殊需求,就是用默认的 1L 就可以,这样可以确保代码一致时反序列化成功。这也可能是造成序列化和反序列化失败的原因,因为不同的序列化id之间不能进行序列化和反序列化。

 序列化前和序列化后的对象的关系

是 "=="还是equal? or 是浅复制还是深复制? 
答案:深复制,反序列化还原后的对象地址与原来的的地址不同
        序列化前后对象的地址不同了,但是内容是一样的,而且对象中包含的引用也相同。换句话说,通过序列化操作,我们可以实现对任何可Serializable对象的“深度复制(deep copy)”——这意味着我们复制的是整个对象网,而不仅仅是基本对象及其引用。对于同一流的对象,他们的地址是相同,说明他们是同一个对象,但是与其他流的对象地址却不相同。也就说,只要将对象序列化到单一流中,就可以恢复出与我们写出时一样的对象网,而且只要在同一流中,对象都是同一个。

静态变量能否序列化

       序列化会忽略静态变量,即序列化不保存静态变量的状态。静态成员属于类级别的,所以不能序列化。即 序列化的是对象的状态不是类的状态。这里的不能序列化的意思,是序列化信息中不包含这个静态成员域。

拓展与总结
1、当一个父类实现序列化,子类自动实现序列化,不需要显式实现Serializable接口;
2、当一个对象的实例变量引用其他对象,序列化该对象时也把引用对象进行序列化;

3、static,transient后的变量不能被序列化;


本文整理自网络分享:

http://www.2cto.com/kf/201405/305380.html

http://blog.csdn.net/wangloveall/article/details/7992448/

http://www.cnblogs.com/xdp-gacl/p/3777987.html

http://my.oschina.net/xianggao/blog/397433

......

0 0
原创粉丝点击