一、定义
序列化:将对象编码成字节流,并从字节流编码中重新构建的对象(将对象写入到IO流中)。换一种说法就是,序列化是用来处理对象流的一种机制,对象流就是将对象的内容进来流化(即将对象转化成二进制)。然后可以对流化的对象进行读写操作或者将其传输于网络之间。
反序列化:将字节流重建成对象称之为反序列化(从IO流中恢复对象)。
二、什么时候需要实现序列化?为什么要实现序列化?
什么时候:
对象序列化可以实现分布式对象(是在面向对象技术的基础上发展起来的,它要解决的主要问题是位于不同进程中的对象之间的调用问题。),RMI(Remote Method Invocation,远程方法调用)要利用对象序列化运行远程主机上的服务,就像在本机上运行对象时一样。
为什么:
(1)首先,序列化就是对实例对象的状态(状态 对象属性而不包括对象方法)进行通用编码并保存(例如:客户端可以调用服务器时,传递的参数是一个 Java 对象,比如叫 cat。服务器并没有那么智能,它并不会知道你传递的是一个 Java 对象,而不是其他类型的数据,它识别不了 Java 对象。Java 对象本质上是 class 字节码,服务器并不能根据这个字节码识别出该 Java 对象。所以,要提供一个公共的格式,不仅 Windows 能识别,你的服务器也能识别的公共的格式。将 Java 对象转换成公共的格式叫做序列化,将公共的格式转换成对象叫做反序列化。),以保证对象的完整性和可传递性。简单来说,序列化,就是为了在不同时间或不同平台的JVM之间共享实例对象。更通俗的解释,当两个进程在进行远程通信时,彼此可以发送各种类型的数据。无论是何种类型的数据,都会以二进制序列的形式在网络上传送。发送方需要把这个Java对象转换为字节序列,才能在网络上传送;接收方则需要把字节序列再恢复为Java对象。
(2)客户端访问了某个能开启会话功能的资源, web服务器就会创建一个与该客户端对应的HttpSession对象,每个HttpSession对象都要占用一定的内存空间。如果在某一时间段内访问站点的用户很多,web服务器内存中就会积累大量的HttpSession对象,消耗大量的服务器内存,即使用户已经离开或者关闭了浏览器,web服务器仍要保留与之对应的HttpSession对象,在他们超时之前,一直占用web服务器内存资源。
web服务器通常将那些暂时不活动但未超时的HttpSession对象转移到文件系统或数据库中保存,服务器要使用他们时再将他们从文件系统或数据库中装载入内存,这种技术称为Session的持久化。将HttpSession对象保存到文件系统或数据库中,需要采用序列化的方式将HttpSession对象中的每个属性对象保存到文件系统或数据库中;将HttpSession对象从文件系统或数据库中装载入内存时,需要采用反序列化的方式,恢复HttpSession对象中的每个属性对象。
(3)假如我有两个类,分别是A和B,B类中含有一个指向A类对象的引用,现在我们对两个类进行实例化{ A a = new A(); B b = new B(); }。这时在内存中实际上分配了两个空间,一个存储对象a,一个存储对象b。接下来我们想将它们写入到磁盘的一个文件中去,就在写入文件时出现了问题!因为对象b包含对对象a的引用,所以系统会自动的将a的数据复制一份到b中,这样的话当我们从文件中恢复对象时(也就是重新加载到内存中)时,内存分配了三个空间,而对象a同时在内存中存在两份。如果我想修改对象a的数据的话,那不是还要搜索它的每一份拷贝来达到对象数据的一致性,这不是我们所希望的!
三、如何实现序列化
(1)实现serializable接口。(该接口没有需要实现的方法,implements Serializable只是为了标注该对象是可被序列化的。)
(2)然后使用一个输出流(如:FileOutputStream)来构造一个ObjectOutputStream(对象流)对象
(3)使用ObjectOutputStream对象的writeObject(Object obj)方法就可以将参数为obj的对象写出(即保存其状态),要恢复的话则用输入流。
例子:
创建一个可序列化的person类,继承了serializable之后,该类的属性皆可被序列化。
1 import java.io.Serializable;
2
3 public class Person implements Serializable {
4
5 private String name=null;
6 private Integer age=null;
7 private Gender gender=null;
8
9 public Person(){
10 System.out.println("non-arg constructor");
11 }
12
13 public Person(String name,Integer age,Gender gender){
14 System.out.println("arg constructor");
15 this.name=name;
16 this.age=age;
17 this.gender=gender;
18 }
19
20 public String getName(){
21 return name;
22 }
23
24 public Integer getAge(){
25 return age;
26 }
27
28 public Gender getGender(){
29 return gender;
30 }
31
32 public void setName(String name){
33 this.name=name;
34 }
35
36 public void setAge(Integer age){
37 this.age=age;
38 }
39
40 public void setGender(Gender gender){
41 this.gender=gender;
42 }
43
44 public String toString(){
45 return "["+name+",age "+age+",gender "+gender+"]";
46 }
47 }
对这个类进行运用,将name和age序列化(也就是把这2个对象转为二进制)
1 import java.io.*;
2
3 // 序列化是将对象状态转换为可保持或传输的格式的过程。
4 // 说明白点就是你可以用对象输出流输出到文件。
5 public class SerializibleTest {
6 public static void main(String args[]) throws Exception{
7
8 // 序列化后生成指定文件
9
10 /** File.seperator:文件路径分隔符
11 * File file=new File("D:" + File.seperator + "person.out");
12 */
13 File file=new File("person.out");
14
15 // 装饰流
16 ObjectOutputStream out = null;
17 out = new ObjectOutputStream(new FileOutputStream(file));
18
19 // 实例化类
20 Person person = new Person("Jack",20,Gender.MALE);
21
22 // 类对象序列化,writeObject方法进行输出保存
23 out.writeObject(person);
24 out.close();
25
26 /**
27 ObjectInputStream oin = null;
28 oin = new ObjectInputStream(new FileInputStream(file));
29
30 Object newPerson = oin.readObject();
31 oin.close();
32
33 System.out.println(newPerson);
34 */
35 }
36 }

浙公网安备 33010602011771号