您的位置:首页 > 编程语言 > Java开发

Java 序列化和反序列化操作

2016-06-29 11:04 471 查看


一、序列化和反序列化:

将对象转化为字节序存储到物理介质上得过程称为序列化;

从物理存储介质上得字节序恢复为对象的过程称为反序列化。

序列化的作用:

a、将对象的字节序列固化到硬盘上, 通常是以一个文件存储起来;

b、为了在网络上传输对象的序列。

例如,常见的web服务器中,当重启或者关闭服务器后,服务器会将对应的session保存下来,但是服务器可能会无法读取session,因此,有必要将session序列化,好让重启后的服务器能够重新读取session。当远端的两个进程通信时,彼此之间以二进制字节序来发送各种类型的数据,发送方需要把对象转化成二进制字节序来传输,接收到需要根据字节序来恢复对象。


二、序列化的方法:

1、将相应的对象实现Serializable 接口,Serializable接口说明了该对象可以序列化,
Serializable是个空接口,只要就是说明该对象可以序列化操作,Java会在传输该对象时进行封装。
在序列化和反序列化过程中需要特殊处理的类必须使用下列准确签名来实现特殊方法:

private void writeObject(java.io.ObjectOutputStream out)
throws IOException
private void readObject(java.io.ObjectInputStream in)
throws IOException, ClassNotFoundException;

writeObject 方法负责写入特定类的对象的状态,以便相应的 readObject 方法可以恢复它。通过调用 out.defaultWriteObject 可以调用保存 Object 的字段的默认机制。该方法本身不需要涉及属于其超类或子类的状态。通过使用 writeObject 方法或使用 DataOutput 支持的用于基本数据类型的方法将各个字段写入 ObjectOutputStream,状态可以被保存。

readObject 方法负责从流中读取并恢复类字段。它可以调用 in.defaultReadObject 来调用默认机制,以恢复对象的非静态和非瞬态字段。defaultReadObject 方法使用流中的信息来分配流中通过当前对象中相应指定字段保存的对象的字段。这用于处理类演化后需要添加新字段的情形。该方法本身不需要涉及属于其超类或子类的状态。通过使用 writeObject 方法或使用 DataOutput 支持的用于基本数据类型的方法将各个字段写入 ObjectOutputStream,状态可以被保存。
 

例如:

java.io.ObjectOutputStream代表对象输出流,它的writeObject(Object obj)方法可对参数指定的obj对象进行序列化,把得到的字节序列写到一个目标输出流中。
  java.io.ObjectInputStream代表对象输入流,它的readObject()方法从一个源输入流中读取字节序列,再把它们反序列化为一个对象,并将其返回。

1 import java.io.Serializable;
2
3 /**
4  * <p>ClassName: Person<p>
5  * <p>Description:测试对象序列化和反序列化<p>
6  * @author xudp
7  * @version 1.0 V
8  * @createTime 2014-6-9 下午02:33:25
9  */
10 public class Person implements Serializable {
11
12     /**
13      * 序列化ID
14      */
15     private static final long serialVersionUID = -5809782578272943999L;
16     private int age;
17     private String name;
18     private String sex;
19
20     public int getAge() {
21         return age;
22     }
23
24     public String getName() {
25         return name;
26     }
27
28     public String getSex() {
29         return sex;
30     }
31
32     public void setAge(int age) {
33         this.age = age;
34     }
35
36     public void setName(String name) {
37         this.name = name;
38     }
39
40     public void setSex(String sex) {
41         this.sex = sex;
42     }
43 }


1 import java.io.File;
2 import java.io.FileInputStream;
3 import java.io.FileNotFoundException;
4 import java.io.FileOutputStream;
5 import java.io.IOException;
6 import java.io.ObjectInputStream;
7 import java.io.ObjectOutputStream;
8 import java.text.MessageFormat;
9
10 /**
11  * <p>ClassName: TestObjSerializeAndDeserialize<p>
12  * <p>Description: 测试对象的序列化和反序列<p>
13  * @author xudp
14  * @version 1.0 V
15  * @createTime 2014-6-9 下午03:17:25
16  */
17 public class TestObjSerializeAndDeserialize {
18
19     public static void main(String[] args) throws Exception {
20         SerializePerson();//序列化Person对象
21         Person p = DeserializePerson();//反序列Perons对象
22         System.out.println(MessageFormat.format("name={0},age={1},sex={2}",
23                                                  p.getName(), p.getAge(), p.getSex()));
24     }
25
26     /**
27      * MethodName: SerializePerson
28      * Description: 序列化Person对象
29      * @author xudp
30      * @throws FileNotFoundException
31      * @throws IOException
32      */
33     private static void SerializePerson() throws FileNotFoundException,
34             IOException {
35         Person person = new Person();
36         person.setName("gacl");
37         person.setAge(25);
38         person.setSex("男");
39         // ObjectOutputStream 对象输出流,将Person对象存储到E盘的Person.txt文件中,完成对Person对象的序列化操作
40         ObjectOutputStream oo = new ObjectOutputStream(new FileOutputStream(
41                 new File("E:/Person.txt")));
42         oo.writeObject(person);
43         System.out.println("Person对象序列化成功!");
44         oo.close();
45     }
46
47     /**
48      * MethodName: DeserializePerson
49      * Description: 反序列Perons对象
50      * @author xudp
51      * @return
52      * @throws Exception
53      * @throws IOException
54      */
55     private static Person DeserializePerson() throws Exception, IOException {
56         ObjectInputStream ois = new ObjectInputStream(new FileInputStream(
57                 new File("E:/Person.txt")));
58         Person person = (Person) ois.readObject();
59         System.out.println("Person对象反序列化成功!");
60         return person;
61     }
62
63 }

代码结果如下:



序列化Person成功后在E盘生成了一个Person.txt文件,而反序列化Person是读取E盘的Person.txt后生成了一个Person对象。


三、注意事项:

1、serialVersionUID 作用:
这是序列化的版本号,如果类或者接口中没有这个serialVersionUID
,那么会出现告警,
默认的方式是 private static final long
serialVersionUID = 1L,
如果没有这个版本号,那么当class文件发生修改后,Java处于安全考虑,Java拒绝载入class文件,也就是说,上面的Person类中增加了一个private int age,那么在此运行时,就会抛出Java.io.InvalidClassException:Person;因为没有指定serialVersion,Java编译器会自动为这个class进行一个算法,得到一个UID,只要这个class发生任何变化,就会产生一个不同的UID,从而保证这个UID是唯一的。因此,当为Person对象增加一个成员后,就会导致2个版本号不一致,影响了序列后操作,因此我们要自己指定这个serialVersion。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息