Java基础系列8:Java的序列化与反序列化(修)

一 简介

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

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

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

对象的序列化主要有两种用途:
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接口实现序列化的区别:

区别SerializableExternalizable
实现负责度实现简单,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,如需转载请自行联系原作者

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/285247.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

[转]nginx学习,看这一篇就够了:下载、安装。使用:正向代理、反向代理、负载均衡。常用命令和配置文件

文章目录 前言一、nginx简介 1. 什么是 nginx 和可以做什么事情2.Nginx 作为 web 服务器3. 正向代理4. 反向代理5. 负载均衡6.动静分离二、Nginx 的安装(Linux:centos为例) 1. 准备工作2. 开始安装3. 运行nginx4. 防火墙问题三、 Nginx 的常用命令和配置文件 1. Nginx常用命令 …

在 .NET 6 中使用 Startup.cs 更简洁的方法

如果您在关注 .NET 6,那么您应该知道,在 .NET 6 项目中,没有 Startup.cs 文件,现在使用了 Program.cs 文件来完成统一的配置。我之前发了一篇使用在 .NET 6 项目中使用 Startup.cs 的文章。在 .NET 6 项目中使用 Startup.cs能否能…

【ArcGIS Pro微课1000例】0005:ArcGIS Pro 2.5基于矢量数据制作拉伸三维地图案例

ArcGIS Pro 2.5中,可以基于某个字段,对矢量数据进行拉伸,制作精美的三维地图。本文以中国省级行政区划数据为例,基于面积字段制作3d地图。 文章目录 1. 新建局部场景2. 地图符号化3. 三维矢量地图制作1. 新建局部场景 打开ArcGIS Pro 2.5,新建局部场景项目,并保存。 2. …

C语言试题144之编写函数输入,输出 5 个学生的数据记录。

📃个人主页:个人主页 🔥系列专栏:C语言试题200例 💬推荐一款模拟面试、刷题神器👉 点击跳转进入网站 ✅作者简介:大家好,我是码莎拉蒂,CSDN博客专家(全站排名Top 50),阿里云博客专家、51CTO博客专家、华为云享专家 1、题目 题目:编写 input()和 output()函数…

第十一次实验总结

知识点总结: 指针、数组和地址间的关系 数组的基地址是在内存中存储数组的起始位置,它是数组中第一个元素(下标为0)的地址,因此数组名本身是一个地址即指针值。 指针是以地址作为值的变量,而数组名的值是一…

Python统计列表中的重复项出现的次数的方法

本文实例展示了Python统计列表中的重复项出现的次数的方法,是一个很实用的功能,适合Python初学者学习借鉴。具体方法如下: 对一个列表,比如[1,2,2,2,2,3,3,3,4,4,4,4],现在我们需要统计这个列表里的重复项,…

分布式(一致性协议)之领导人选举( DotNext.Net.Cluster 实现Raft 选举 )

分布式(一致性协议)之领导人选举( DotNext.Net.Cluster 实现Raft 选举 )继分布式锁之后的又一高可用技术爽文之分布式领导选举 或者说 分布式一致性协议的实现分布式选举是实现高可用的必备技术,想实现主从,就必须得有选举的策略,有主从才会有…

投巧解决JavaScript split方法出现空字符的问题

直接使用split,前后各有一个“”值。 >> var str,a,b,c,d,e,f,; >> str.split(,);//(8) ["", "a", "b", "c", "d", "e", "f", ""]临时方法:split后&…

C语言试题146之反向输出一个链表

📃个人主页:个人主页 🔥系列专栏:C语言试题200例 💬推荐一款模拟面试、刷题神器👉 点击跳转进入网站 ✅作者简介:大家好,我是码莎拉蒂,CSDN博客专家(全站排名Top 50),阿里云博客专家、51CTO博客专家、华为云享专家 1、题目 题目:反向输出一个链表 2 、温馨提…

【ArcGIS Pro微课1000例】0006:ArcGIS Pro 2.5三维显示DEM数字高程模型

通过ArcGIS的学习,我们知道,ArcScene可以实现二维数据的三维显示,是将二维数据(例如DEM)进行自定义表面浮动拉伸。那么ArcGIS Pro中能不能实现DEM的三维显示呢? ArcScene三维显示结果: 目前所采用的ArcGIS Pro 2.5版本还不能直接将DEM进行三维显示,我们的做法是参照Ar…

中国古代历朝首都一览

【五帝时期】(约公元前26世纪初—公元前2070年) 『黄帝』有熊(今河南郑州新郑) 『颛顼』帝丘(今河南濮阳) 『帝喾』帝丘(今河南濮阳)、西亳(今河南洛阳偃师西&#xff09…

程序员的自我修养:有助于提高沟通能力的7本书

直接影响工作效率的四种能力:沟通能力、自学能力、自我管理能力、问题解决能力。提高沟通能力,是程序员提高自我修养的必要条件。相信很多人跟我一样,性格内向,信仰技术,很少有跟人说话的愿望,只是想看代码…

玩转 Linux 之:磁盘分区、挂载知多少?

转载于:http://my.oschina.net/leejun2005/blog/290073 在做日志机扩容的时候,发现运维同学将一块硬盘的挂载点没有同以前的日志机保持一致,考虑到这会给日后的维护带来麻烦,于是尝试着手修改,在修改的同时&#xff0c…

C# NanoFramework 点灯和按键 之 ESP32

本来周末是要搞个大的,WIFI 和 Web网页之类的,奈何搞了两天,并与外国友人聊过后,才发现是固件有问题,晚上与大佬进行交流后才发现,原来ESP32S的官方固件有问题,搞不了。所以,建议买的…

【ArcGIS Pro微课1000例】0002:ArcGIS Pro 2.5二三维联动显示

ArcGIS Pro是一款全新的桌面应用程序,它改变了桌面GIS的工作方式,以满足新一代WebGIS应用模式。ArcGIS Pro采用Ribbon界面风格,给人全新的用户体验。它作为一个高级的应用程序,可以对来自本地、ArcGIS Online、或者Portal for ArcGIS的数据进行可视化、编辑、分析。同时,实…

Spring Boot 解决跨域Cors问题

后端主要代码: (http://localhost:8080/ ) /*WebCorsConfig.java*/ package com.example.demo.Controller;import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.config.annotation.CorsR…

C语言试题147之创建一个链表并且排序输出这个链表

📃个人主页:个人主页 🔥系列专栏:C语言试题200例 💬推荐一款模拟面试、刷题神器👉 点击跳转进入网站 ✅作者简介:大家好,我是码莎拉蒂,CSDN博客专家(全站排名Top 50),阿里云博客专家、51CTO博客专家、华为云享专家 1、题目 题目:创建一个链表并且排序输出这…

DOM节点创建(jQuery)

1DOM创建节点及节点属性 通过JavaScript可以很方便的获取DOM节点,从而进行一系列的DOM操作。但实际上一般开发者都习惯性的先定义好HTML结构,但这样就非常不灵活了。 试想下这样的情况:如果我们通过AJAX获取到数据之后然后才能确定结构的话&a…

PHP中刷新输出缓冲

2019独角兽企业重金招聘Python工程师标准>>> http://www.cnblogs.com/mutuan/archive/2012/03/18/2404957.html 转载于:https://my.oschina.net/wuzhencan/blog/652259

2021最新计算机二级C语言试题

一、选择题 (1) 下面叙述正确的是( C ) A. 算法的执行效率与数据的存储结构无关 B. 算法的空间复杂度是指算法程序中指令(或语句)的条数 C. 算法的有穷性是指算法必须能在执行有限个步骤之后终止 D. 以上三种描述都不对 (2) 以下数据结构中不属于线性数据结构的是( C ) A…