码迷,mamicode.com
首页 > 编程语言 > 详细

Java基础:序列化(Serializable)与反序列化

时间:2015-08-01 00:57:30      阅读:188      评论:0      收藏:0      [点我收藏+]

标签:

在学习IO中的ObjectOutputStream和ObjectInputStream时,会涉及到序列化和反序列化的应用,那么它们是什么?

一、概念

序列化:把对象转换为字节序列的过程,叫做对象的序列化。

反序列化:把字节序列恢复为对象的过程,叫做对象的反序列化。

 

二、作用

主要有两种用途:

1.把对象的字节序列永久保存在硬盘中,也就是把内存中的数据(对象)持久化处理。

2.可以在网络上传输对象的字符序列,对象不再局限于本地使用。

 

无论那种用途,实际上都是为了保存在内存中的各种对象的状态(也就是实例变量,不是方法),并且可以把保存的对象状态再读出来。这是java提供的一种保存对象状态的机制。

 

三、应用

在开头有提到,在java.io包中有两个序列化对象的类,分别为:ObjectOutputStream将对象写入字节流,ObjectInputStream将字节流重构为对象。

需要注意的是,被序列化的对象必须要实现Serializable或者Externalizable接口。

例子1:(为了方便阅读,异常都做抛处理):

 1 import java.io.File;
 2 import java.io.FileInputStream;
 3 import java.io.FileOutputStream;
 4 import java.io.ObjectInputStream;
 5 import java.io.ObjectOutputStream;
 6 import java.io.Serializable;
 7 
 8 public class Test {
 9     public static void main(String[] args) throws Exception{
10         Person p = new Person("zhangsan",20);
11         serializePerson(p);
12         Person p1 = deserializePerson();
13         System.out.println(p1);        //结果打印zhangsan:20。
14     }
15 
16 //    序列化
17     private static void serializePerson(Object obj) throws Exception {
18         ObjectOutputStream out= new ObjectOutputStream(new FileOutputStream(new File("c:\\obj.txt")));
19         out.writeObject(obj);
20         System.out.println("序列化成功");
21         out.close();
22     }
23     
24 //    反序列化
25     private static Person deserializePerson() throws Exception {
26         ObjectInputStream in = new ObjectInputStream(new FileInputStream("c:\\obj.txt"));
27         Person p1 = (Person)in.readObject();
28         System.out.println("反序列化成功");
29         in.close();
30         return p1;
31     }
32     
33 }
34 
35 
36 class Person implements Serializable {
37 //    注意,如果不指定serialVersionUID,序列化时会按默认方式进行,也会产生serialVersionUID。
38 //    但是如果后来有修改类中代码,序列化产生的serialVersionUID也会改变,这时反序列化就会失败,发生异常。
39     private static final long serialVersionUID = 1L;
40     private String name;
41     private int age;
42     Person() {
43         System.out.println("空参数构造函数");
44     }
45     public Person(String name, int age) {
46         System.out.println("有参数构造函数");
47         this.name = name;
48         this.age = age;
49     }
50     
51     public String toString() {
52         return name+":"+age;
53     }
54 }

以上代码运行结果为:

有参数构造函数
序列化成功
反序列化成功
zhangsan:20

从结果可以看出,反序列化时,并没用通过Person类的构造函数,而是根据序列化的数据创建Person对象的。

要注意的是,默认serialVersionUID的取值是Java运行时,根据类的内部细节自动生成的。如果对类的源代码作了修改,再重新编译,新生成的类文件的serialVersionUID的取值有可能也会发生变化。类的serialVersionUID的默认值完全依赖于Java编译器的实现,对于同一个类,用不同的Java编译器编译,有可能会导致不同的 serialVersionUID,也有可能相同。为了提高serialVersionUID的独立性和确定性,强烈建议在一个可序列化类中显示的定义serialVersionUID,为它赋予明确的值。

显式定义serialVersionUID可以实现两种目的:

1.若想不同版本的类(类有做过修改)序列化后,都能成功反序列化(兼容),就需要确保类的不同版本的类具有相同的serialVersionUID;

2.若不想不同版本的类序列化后还能成功反序列化,就让不同版本的类具有不同的serialVersionUID

 

例子2:

先序列化:

 1 public class TestSerialze {
 2     public static void main(String[] args) throws Exception{
 3         Person p = new Person("zhangsan",20);
 4         serializePerson(p);
 5     }
 6 
 7 //    序列化
 8     private static void serializePerson(Object obj) throws Exception {
 9         ObjectOutputStream out= new ObjectOutputStream(new FileOutputStream(new File("c:\\obj.txt")));
10         out.writeObject(obj);
11         System.out.println("序列化成功");
12         out.close();
13     }
14 }
15 
16 
17 class Person implements Serializable {
18 //    注意,如果不指定serialVersionUID,序列化时会按默认方式进行,也会产生serialVersionUID。
19 //    但是如果修改类中内容后,序列化产生新的serialVersionUID,跟原来不一样,这时反序列化就会失败,发生异常。
20     private static final long serialVersionUID = 1L;
21     private String name;
22     private int age;
23 //    静态成员属于类,不能被序列化。
24     private static int count;
25 //    瞬态也不能被序列化。
26     transient private int key;
27     
28     Person() {
29         System.out.println("空参数构造函数");
30     }
31     public Person(String name, int age) {
32         System.out.println("有参数构造函数");
33         this.name = name;
34         this.age = age;
35         count++;
36         key++;
37     }
38     
39     public String toString() {
40         return name+":"+age+"..."+count+"..."+key;
41     }
42 }

后反序列化:

import java.io.FileInputStream;
import java.io.ObjectInputStream;

public class TestDeserialze {
    public static void main(String[] args) throws Exception{
        Object obj = deserializeObject();
        System.out.println(obj);
    }

    private static Object deserializeObject() throws Exception {
        ObjectInputStream in = new ObjectInputStream(new FileInputStream("c:\\obj.txt"));
        Object obj = in.readObject();
        System.out.println("反序列化成功");
        in.close();
        return obj;
    }
}

反序列化得到的结果是:

反序列化成功
zhangsan:20...0...0

以上可以看出被static和transient修饰的成员变量无法被序列化。

Java基础:序列化(Serializable)与反序列化

标签:

原文地址:http://www.cnblogs.com/challengingtime/p/4693444.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!