一 简介

对象序列化就是把一个对象变成二进制的数据流的一种方法,通过对象序列化可以方便地实现对象的传输和存储。

把对象转换为字节序列的过程称为对象的序列化

把字节序列恢复为对象的过程称为对象的反序列化

对象的序列化主要有两种用途:
1) 把对象的字节序列永久地保存到硬盘上,通常存放在一个文件中;
2) 在网络上传送对象的字节序列。

对象序列化包括如下步骤:
1) 创建一个对象输出流,它可以包装一个其他类型的目标输出流,如文件输出流;
2) 通过对象输出流的writeObject()方法写对象。

对象反序列化包括如下步骤:
1) 创建一个对象输入流,它可以包装一个其他类型的源输入流,如文件输入流;
2) 通过对象输入流的readObject()方法读取对象。

在很多应用中,需要对某些对象进行序列化,让它们离开内存空间,入住物理硬盘,以便长期保存。比如最常见的是Web服务器中的Session对象,当有 10万用户并发访问,就有可能出现10万个Session对象,内存可能吃不消,于是Web容器就会把一些seesion先序列化到硬盘中,等要用了,再把保存在硬盘中的对象还原到内存中。

当两个进程在进行远程通信时,彼此可以发送各种类型的数据。无论是何种类型的数据,都会以二进制序列的形式在网络上传送。发送方需要把这个Java对象转换为字节序列,才能在网络上传送;接收方则需要把字节序列再恢复为Java对象。

二 Java中的序列化API

如果一个类的对象想被序列化,那么该对象所在的类必须实现java.io.Serializable接口,此接口的定义如下:

public interface Serializable{}

可以发现此接口并没有定义任何的方法,只是一个标识接口,表示一个类可以被序列化,如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
package cn.zifangsky.serializable;
import java.io.Serializable;
public class Person implements Serializable {
    private static final long serialVersionUID = 2651243789670519969L;
    private String name;
    private int age;
    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }
    public String toString() {
        return "Person [name=" + name + ", age=" + age + "]";
    }
}

就像上面这个Person类一样,实现了序列化接口表明此类的对象可以经过二进制的数据流进行传输了。但是如果想要完成对象的输入和输出,还需要借助对象输出流(ObjectOutputStream)和对象输入流(ObjectInputStream)

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

只有实现了Serializable或Externalizable接口的类的对象才能被序列化。Externalizable接口继承自 Serializable接口,实现Externalizable接口的类完全由自身来控制序列化的行为,而仅实现Serializable接口的类可以 采用默认的序列化方式 。

三 使用Serializable接口实现的实例

首先定义了一个实现了Serializable接口WebSite的实体类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
package cn.zifangsky.serializable;
import java.io.Serializable;
public class WebSite implements Serializable {
    private static final long serialVersionUID = 1835573222135484360L;
    private String siteName;
    private String siteUrl;
    private String webMaster;
    public WebSite() {
    }
    public WebSite(String siteName, String siteUrl, String webMaster) {
        this.siteName = siteName;
        this.siteUrl = siteUrl;
        this.webMaster = webMaster;
    }
    public String getSiteName() {
        return siteName;
    }
    public void setSiteName(String siteName) {
        this.siteName = siteName;
    }
    public String getSiteUrl() {
        return siteUrl;
    }
    public void setSiteUrl(String siteUrl) {
        this.siteUrl = siteUrl;
    }
    public String getWebMaster() {
        return webMaster;
    }
    public void setWebMaster(String webMaster) {
        this.webMaster = webMaster;
    }
    public String toString() {
        return "WebSite [siteName=" + siteName + ", siteUrl=" + siteUrl + ", webMaster=" + webMaster + "]";
    }
}

然后进行序列化和反序列化测试:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
package cn.zifangsky.serializable;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
public class TestSerialize {
    public static void main(String[] args) throws FileNotFoundException, IOException, ClassNotFoundException {
        TestSerialize.serializeWebSite();
        TestSerialize.deserializeWebSite();
    }
     
    /**
     * 使用ObjectOutputStream 序列化WebSite
     * @throws IOException 
     * @throws FileNotFoundException 
     
     * */
    public static void serializeWebSite() throws FileNotFoundException, IOException{
        WebSite webSite = new WebSite();
        webSite.setSiteName("zifangsky的个人博客");
        webSite.setSiteUrl("http://www.zifangsky.cn");
        webSite.setWebMaster("zifangsky");
         
        //序列化
        ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream(new File("C:/Users/Administrator/Desktop/test.txt")));
        objectOutputStream.writeObject(webSite);
        objectOutputStream.flush();
        objectOutputStream.close();
    }
     
    /**
     * 使用ObjectInputStream 反序列化WebSite
     * @throws IOException 
     * @throws FileNotFoundException 
     * @throws ClassNotFoundException 
     
     * */
    public static void deserializeWebSite() throws FileNotFoundException, IOException, ClassNotFoundException{
        ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream(new File("C:/Users/Administrator/Desktop/test.txt")));
        //反序列化
        WebSite webSite = (WebSite) objectInputStream.readObject();
        objectInputStream.close();
        System.out.println(webSite);
    }
     
}

输出:

1
WebSite [siteName=zifangsky的个人博客, siteUrl=http://www.zifangsky.cn, webMaster=zifangsky]

四 使用Externalizable接口实现的实例

被Serializable接口声明的类的对象的内容都将被序列化,如果现在用户希望自己制定序列化的内容,则可以让一个类实现Externalizable接口,此接口的定义如下:

public interface Externalizable extends java.io.Serializable {
 
    void writeExternal(ObjectOutput out) throws IOException;

void readExternal(ObjectInput in) throws IOException, ClassNotFoundException;
}

其中,这两个方法的作用是:

i)writeExternal(ObjectOutput out) :在此方法中制定要保存的属性信息,对象序列化时调用

ii)readExternal(ObjectInput in) : 在此方法中读取被保存的信息,对象反序列化时调用

下面将以一个具体的实例来简单说明序列化和反序列化过程:

(1)实现了Externalizable接口的实体类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
package cn.zifangsky.serializable;
import java.io.Externalizable;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
public class ExternalizableDemo implements Externalizable{
    private String name;
    static {
        System.out.println("调用静态代码块");
    }
    public ExternalizableDemo() {
        System.out.println("调用无参构造方法");
    }
    public ExternalizableDemo(String name) {
        this.name = name;
        System.out.println("调用有参构造方法");
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public String toString() {
        return "ExternalizableDemo [name=" + name + "]";
    }
     
    /**
     * ObjectOutputStream会调用writeExternal(ObjectOutput out))这个方法进行序列化
     * */
    public void writeExternal(ObjectOutput out) throws IOException {
        out.writeObject(name);
    }
    /**
     * ObjectInputStream会调用readExternal(ObjectInput in)这个方法进行反序列化
     * */
    public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
        name = (String) in.readObject();
    }
}

(2)然后进行序列化和反序列化测试:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
package cn.zifangsky.serializable;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
public class TestExternalizable {
    public static void main(String[] args) throws FileNotFoundException, IOException, ClassNotFoundException {
        ExternalizableDemo demo = new ExternalizableDemo("hello");
        // 序列化
        ObjectOutputStream objectOutputStream = new ObjectOutputStream(
                new FileOutputStream(new File("C:/Users/Administrator/Desktop/test2.txt")));
        objectOutputStream.writeObject(demo);
        objectOutputStream.flush();
        objectOutputStream.close();
         
        //反序列化
        ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream(new File("C:/Users/Administrator/Desktop/test2.txt")));
        ExternalizableDemo demo2 = (ExternalizableDemo) objectInputStream.readObject();
        objectInputStream.close();
        System.out.println(demo2);     
    }
}

输出:

1
2
3
4
调用静态代码块
调用有参构造方法
调用无参构造方法
ExternalizableDemo [name=hello]

注:

(1)使用Externalizable进行序列化时,当读取对象时,会调用被序列化类的无参构造器去创建一个新的对象,然后再将被保存对象的字段的值分别填充到新对象中

(2)Externalizable接口与Serializable接口实现序列化的区别:

区别 Serializable Externalizable
实现负责度 实现简单,Java对其有内建支持 实现负责,由开发人员自己完成
执行效率 所有对象由Java统一保存,性能较低 开发人员自己决定保存那些对象,可能造成速度提升
保存信息 保存时占用空间大 部分存储,可能造成空间减小

(3)一个对象被序列化后,到底哪些内容被保存了下来,是属性还是方法?

答:只有属性被序列化。因为每个对象都有相同的方法,但是每个对象的属性却不一定相同,因此对象保存的只有属性信息,那么同样道理在进行序列化操作时也只有属性被序列化

五 transient关键字

当使用Serializable接口实现序列化操作时,如果一个对象中的某个属性不希望被序列化,那么就可以使用transient关键字进行声明

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
package cn.zifangsky.serializable;
import java.io.Serializable;
public class WebSite implements Serializable {
    private static final long serialVersionUID = 1835573222135484360L;
    private String siteName;
    private String siteUrl;
    private transient String webMaster;
    public WebSite(String siteName, String siteUrl, String webMaster) {
        this.siteName = siteName;
        this.siteUrl = siteUrl;
        this.webMaster = webMaster;
    }
    public String toString() {
        return "WebSite [siteName=" + siteName + ", siteUrl=" + siteUrl + ", webMaster=" + webMaster + "]";
    }
}

在上面这个类中,不希望webMaster这个属性被序列化,因此把它用transient关键字进行修饰,接下来就是序列化与反序列化测试:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
package cn.zifangsky.serializable;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
public class TestSerialize {
    public static void main(String[] args) throws FileNotFoundException,
            IOException, ClassNotFoundException {
        TestSerialize.serializeWebSite();
        TestSerialize.deserializeWebSite();
    }
    /**
     * 使用ObjectOutputStream 序列化WebSite
     
     * @throws IOException
     * @throws FileNotFoundException
     
     * */
    public static void serializeWebSite() throws FileNotFoundException,
            IOException {
        WebSite webSite = new WebSite("zifangsky的个人博客","http://www.zifangsky.cn","zifangsky");
        // 序列化
        ObjectOutputStream objectOutputStream = new ObjectOutputStream(
                new FileOutputStream(new File(
                        "C:/Users/Administrator/Desktop/test.txt")));
        objectOutputStream.writeObject(webSite);
        objectOutputStream.flush();
        objectOutputStream.close();
    }
    /**
     * 使用ObjectInputStream 反序列化WebSite
     
     * @throws IOException
     * @throws FileNotFoundException
     * @throws ClassNotFoundException
     
     * */
    public static void deserializeWebSite() throws FileNotFoundException,
            IOException, ClassNotFoundException {
        ObjectInputStream objectInputStream = new ObjectInputStream(
                new FileInputStream(new File(
                        "C:/Users/Administrator/Desktop/test.txt")));
        // 反序列化
        WebSite webSite = (WebSite) objectInputStream.readObject();
        objectInputStream.close();
        System.out.println(webSite);
    }
}

输出:

1
WebSite [siteName=zifangsky的个人博客, siteUrl=http://www.zifangsky.cn, webMaster=null]

从上面的输出可以看出,webMaster这个属性并没有被序列化

本文转自 pangfc 51CTO博客,原文链接:http://blog.51cto.com/983836259/1758247,如需转载请自行联系原作者

Java基础系列8:Java的序列化与反序列化(修)相关推荐

  1. Java基础系列【导读】

    Java基础系列导读 Java基础 JaveWEB Java基础 基础系列[一]-- Java语言介绍 基础系列[二]-- 环境搭建 基础系列[三]-- Java基础语法 基础系列[四]-- 面向对象 ...

  2. 夯实Java基础系列22:一文读懂Java序列化和反序列化

    本系列文章将整理到我在GitHub上的<Java面试指南>仓库,更多精彩内容请到我的仓库里查看 https://github.com/h2pl/Java-Tutorial 喜欢的话麻烦点下 ...

  3. 夯实Java基础系列14:深入理解Java枚举类

    本系列文章将整理到我在GitHub上的<Java面试指南>仓库,更多精彩内容请到我的仓库里查看 https://github.com/h2pl/Java-Tutorial 喜欢的话麻烦点下 ...

  4. Java基础系列五 面向对象程序设计

    Java基础系列第一章 初识Java语言 Java基础系列第二章 Java语言基础 Java基础系列第三章 Java流程控制 Java基础系列第四章 Java数组与字符串 Java基础系列第五章 面向 ...

  5. string substring的用法_夯实Java基础系列3:一文搞懂String常见面试题,从基础到实战...

    本系列文章将整理到我在GitHub上的<Java面试指南>仓库,更多精彩内容请到我的仓库里查看 https://github.com/h2pl/Java-Tutorial 喜欢的话麻烦点下 ...

  6. 基础的java增删改查,Java基础系列(基础):Java使用Cookie增删改查操作!

    什么是Cookie? Cookie是由W3C组织提出,最早由NetScape社区发展的一种机制. Cookie是存储于访问者的计算机中的变量.每当同一台计算机通过浏览器请求某个页面时,就会发送这个co ...

  7. java中this_夯实Java基础系列7:一文读懂Java 代码块和执行顺序

    目录 #java中的构造方法 #构造方法简介 #构造方法实例 #例-1 #例-2 #java中的几种构造方法详解 #普通构造方法 #默认构造方法 #重载构造方法 #java子类构造方法调用父类构造方法 ...

  8. java复习系列[1] - Java 基础

    文章目录 Java 基础 final static Java的switch支持的数据类型 goto (扫盲 - 一般不用) String 不可变 不可变的优势 序列化 序列化的 *serialVers ...

  9. [转载] 夯实Java基础系列8:深入理解Java内部类及其实现原理

    参考链接: Java内部类 本系列文章将整理到我在GitHub上的<Java面试指南>仓库,更多精彩内容请到我的仓库里查看 https://github.com/h2pl/Java-Tut ...

  10. java基础系列十七(时间日期转换)

    目录 一.概述 二.基础知识 2.1 时区 2.2 格林威治时间 2.3 时间戳 三.Date/Calendar/SimpleDateFormat 3.1 Date 3.2 Calendar 3.3 ...

最新文章

  1. IntelliJ IDEA乱码问题解决方法
  2. 【Android工具】wifi概观360中文专业版,wifi overview 360 pro,wifi信息查看工具
  3. jquery-uploadifyv3.2.1 文件上传插件 学习
  4. UVa 208 Firetruck【回溯】
  5. ios退款 怎么定位到是哪个用户_哪个浏览器兼容性最好用?看看用户都是怎么评价的吧...
  6. 商城网站该如何选择虚拟主机
  7. Win 10 Revit 2019 安装过程,亲自踩的一遍坑,有你想要的细节
  8. 图嵌入综述 (arxiv 1709.07604) 译文第一、二章
  9. usb深度检查 清理_红桥区清理隔油池一般多少钱
  10. 当推荐系统遇见知识图谱会发生什么?
  11. 快速排序方法——python实现
  12. 第三章 数据链路层[课后习题+练习题]
  13. css vw vh ie9,css3中calc、vw、vh、vmin、vmax 属性的应用及兼容性详解
  14. meethigher-逆向破解今日校园App加密值
  15. 多线程实现 qq 群聊的服务端和客户端
  16. 全面曝光POS机支付行业三大痛点,许多支付人为此献出劳动成果
  17. RHEL 8.2 镜像
  18. 数据库发展史(引用1)
  19. bugly的全量更新与热更新
  20. 使用Typora+PicGo配置Gitee图床

热门文章

  1. 老姚浅谈:怎么学JavaScript?
  2. 如何读懂并写出装逼的函数式代码 1
  3. ​css3属性选择器总结
  4. php-fpm with php-5.3.2 + APC
  5. 【原创】erlang 模块之 application
  6. Android两个注意事项.深入了解Intent和IntentFilter(两)
  7. jqurey操作radio总结
  8. delphi 算术溢出解决方法_性能优化系列:JVM 内存划分总结与内存溢出异常详解分析...
  9. MySQL时间格式TIMESTAMP和DATETIME的区别
  10. Python 调度算法 死锁 静动态链接 分页分段