IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 网络协议 -> 高薪程序员&面试题精讲系列29之为什么要进行序列化与反序列化? -> 正文阅读

[网络协议]高薪程序员&面试题精讲系列29之为什么要进行序列化与反序列化?

一. 面试题及剖析

1. 今日面试题

什么是序列化和反序列化?

为什么要进行序列化和反序列化?

怎么进行序列化和反序列化?

......

2. 题目剖析

Java开发中,我们经常要进行信息的传输,传输的数据类型可以包括基本类型、String等对象类型,也可以是文本、图片、音频、视频等,那么我们在进行数据传递的过程中,如何确保这些信息的高效、安全传输?

另外随着现在分布式项目的开发,我们在Java项目中会经常使用各种RPC进程间通信技术,比如HttpClient、URLConnection、Dubbo、RestTemplate、Ribbon、Feign、Netty等各种框架。所有的这些通信框架都可以实现跨进程传递数据,而传递的数据如果是对象类型,无一例外都会要求该对象必须实现序列化。

所以面试官在考察我们对这些框架的底层掌握情况时,一般都会让我们讲一下这些通信框架的底层实现,而所谓的底层实现,其中的一个回答方向就是要讲清楚这些通信框架中是如何进行对象序列化的。

二. 什么是序列化和反序列化

1. 序列化

Java序列化就是把Java对象转换成有序的字节流的过程,它是一种处理对象流的机制,可以很方便的保存内存中的Java对象状态,并可以进行重建。同时序列化也方便了对象传输,使得该对象能够在网络上传输或者保存在本地文件中,并且确保了对象在传递和保存过程中的完整性和可传递性。

如果你看过小说《三体》,就可以对序列化和反序列化有着比较好的理解了。我们可以把序列化的过程,理解为歌者文明对宇宙使用了二向箔进行了降维打击,把三维世界变成了二维世界。

虽然《三体》小说中的降维打击是不能逆转的,但是Java中的序列化和反序列化却是可以互相可逆转的。

2. 反序列化

Java反序列化就是把有序的字节序列重新恢复为Java对象的过程。一般客户端从文件中或网络上获得序列化后的对象字节流后,会根据字节流中所保存的对象状态及描述信息,通过反序列化重建对象,相当于再把上面的二维世界再恢复为三维世界。

三. 为什么要序列化和反序列化

那为什么要进行序列化和反序列化呢?其实要回答这个问题,这里我们只需要回答出序列化和反序列化的作用于优点即可。

1. 序列化和反序列化的作用

根据上面序列化和反序列化的概念,我们可以提取出序列化和反序列化的2个核心作用:

  1. 可以把对象的字节序列持久地保存在硬盘上,比如保存在一个文件中;
  2. 可以在网络上安全的传送对象的字节序列。

举个栗子,假如我们的Web 服务器上,要存储10w万个用户的并发会话信息,这时就可能要保存10万个Session 对象,这时服务器的内存很可能会吃不消。那么这时候,就可以把一些 Session 先序列化,让这些Session离开内存空间,持久化存储到硬盘中。当后面需要调用这些Session时,再把保存在硬盘中的Session对象还原到内存中。

另外当两个进程之间进行远程通信时,彼此可以发送各种类型的数据,包括文本、图片、音频、视频等, 而这些数据都会以二进制序列的形式在网络上传送。同样的序列化与反序列化则实现了进程通信间的对象传送,发送方需要把这个Java对象转换为字节序列,才能在网络上传送;接收方则需要把字节序列再恢复为Java对象。

2. 序列化和反序列化的优点

所以根据上面序列化的作用,我们可以总结出序列化和反序列化的优点,如下:

  • 对象序列化可以实现分布式对象的存储与传输。可以实现在本地机器上运行远程机器里的对象。
  • 序列化不仅可以保留一个对象的数据,而且还可以递归保存对象引用的数据。我们可以利用对象的"深复制",即复制对象本身及对象的引用,序列化一个对象可以得到整个对象序列。
  • 序列化可以将内存中的对象写入到文件或数据库中。我们可以将某个对象序列化后持久化为文件,下次读取时只需将文件中的数据反序列化,就可以将原先的对象再还原到内存中。
  • 可以统一对象、文件、数据等信息的格式。序列化以后就都是字节流了,无论之前的数据是什么格式的内容,序列化之后都变成了有序的字节流,方便了我们的传输和保存。

所以,基于序列化和反序列化的作用与优点,我们在开发时就需要这种技术。

四. 什么时候进行序列化和反序列化

既然序列化和反序列化这么重要,有这么多优点,那我们该什么时候进行序列化和反序列化呢?这里?壹哥?先给各位说一个常见的使用场景:

只要我们想对内存中的对象进行持久化,或者想进行网络传输, 这时都需要进行序列化和反序列化。

所以进行序列化和反序列化的情况,一般就两种:

  1. 一般Java对象的生命周期都比Java虚拟机的要短,实际应用中我们希望在JVM停止运行之后能够持久化指定的对象,这时候就需要把对象进行序列化之后进行持久化保存。
  2. 需要把Java对象通过网络进行传输的时候。因为数据只能够以二进制的形式在网络中进行传输,因此当把对象通过网络发送出去之前,需要先序列化成二进制数据,在接收端读到二进制数据之后反序列化成Java对象。

总的来说,就是如果我们想将内存中的对象持久化到磁盘、数据库中, 或者当我们需要与浏览器进行交互时, 需要实现RPC远程通信时, 都要进行序列化和反序列化。

五. 如何实现序列化和反序列化

1. 序列化与反序列化API简介

在Java中实现序列化和反序列化操作,我们可以使用Serializable接口,再结合使用ObjectOutputStream(对象输出流) 和ObjectInputStream(对象输入流)即可实现,所有相关API如下:

  • Serializable用于标识某个类对象可以被序列化,如果不标识,则不可序列化,该接口中并没有提供任何方法。
  • SerialVersionUid序列化版本号:该值一般是 Java 运行时根据类的内部细节自动生成的。如果有人对类的源代码作了修改,再重新编译,新生成类文件的 serialVersionUID 取值有可能也会发生变化。所以我们可以判断反序列化时类的版本号与序列化时类的版本号一致,来区分我们要序列化类的版本,另外如果不一致会出现版本不一致异常;
  • transient关键字用于忽略我们不希望进行序列化的属性字段;
  • ObjectOutputStream通过使用 writeObject(Object object) 方法,可以将对象以二进制格式进行持久化存储;
  • ObjectInputStream通过使用 readObject()方法,可以从输入流中读取二进制流,转换成对象。

2. 示例代码

接下来 壹哥 通过编写一段示例代码,给大家展示如何实现序列化和反序列化。

2.1 定义Person类

这里我定义了一个Peron类,让该类实现Serializable接口,并且给该类中生成一个serialVersionUID序列号

@Data
public class Person implements Serializable{

    /**
     * 序列化编号,定义序列化版本,在序列化与反序列化之间进行校验
     */
    private static final long serialVersionUID = 3604972003323896788L;

    private Integer id;

    private String name;

    /**
     * transient: 忽略不需要实现序列化的属性
     */
    private transient Integer age;
    
    //Getter...
    
    //Setter...

}

注意:

如果该类不实现Serializable序列化接口,在进行序列化时会出现如下异常。

Exception in thread "main" java.io.NotSerializableException: com.yyg.interview.serializable.Person
	at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1184)
	at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:348)
	at com.yyg.interview.serializable.SerializePersonTest.serializePerson(SerializePersonTest.java:25)
	at com.yyg.interview.serializable.SerializePersonTest.main(SerializePersonTest.java:43)

2.2 实现序列化与反序列化

Person中实现了序列化接口之后,接下来我再进行序列化与反序列化操作,主要是使用ObjectOutputStream(对象输出流) 和ObjectInputStream(对象输入流) 这两个I/O流API。

public class SerializePersonTest {

    /**
     * 序列化Person对象
     */
    private static void serializePerson() throws FileNotFoundException,
            IOException {
        Person person = new Person();
        person.setId(1);
        person.setName("一一哥");
        person.setAge(18);
        //ObjectOutputStream对象输出流,将Person对象持久化存储到E盘的Person.txt文件中,完成对Person对象的序列化操作
        ObjectOutputStream oo = new ObjectOutputStream(
                new FileOutputStream(new File("E:/Person.txt")));
        oo.writeObject(person);
        System.out.println("Person对象序列化成功!");
        oo.close();
    }

    /**
     * 反序列Person对象
     */
    private static Person deserializePerson() throws Exception, IOException {
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream(
                new File("E:/Person.txt")));
        Person person = (Person) ois.readObject();
        System.out.println("Person对象反序列化成功!");
        return person;
    }

    public static void main(String[] args) throws Exception {
        //序列化Person对象
        serializePerson();

        //反序列Peron对象
        Person person = deserializePerson();
        System.out.println(MessageFormat.format("sex={0},name={1},age={2}",person.getId(), person.getName(), person.getAge()));
    }

}

2.3 执行结果

代码执行完毕后,我们可以看到序列化与反序列化的执行结果。因为Person类的age字段使用了transient关键字,所以不会进行序列化操作。Person对象被持久化保存到了Person.txt文件中,该文件如果打开之后会看到一堆无意义的字符序列。

3. Externalizable接口(可选)

另外我们其实也可以通过实行Externalizable接口来实现序列化,这是Serializable接口的一个子类,我们可以通过writeExternal()和readExternal()方法来进行序列化和反序列化操作。

六. 结语

最后 壹哥 把今天的面试题给大家做个简单的总结,今天面试题回答的要点如下。

  1. 先回答序列化与反序列化的概念;
  2. 回答出序列化与反序列化的作用与优点;
  3. 回答实现序列化与反序列化的方式有几种:
    1. Serializable接口及其功能,序列号的作用;
    2. ObjectInputStream 和ObjectOutputStream 两个IO类的使用;
    3. 了解Externalizable接口。
  4. 另外要清楚SerialVersionUid号的作用。
  网络协议 最新文章
使用Easyswoole 搭建简单的Websoket服务
常见的数据通信方式有哪些?
Openssl 1024bit RSA算法---公私钥获取和处
HTTPS协议的密钥交换流程
《小白WEB安全入门》03. 漏洞篇
HttpRunner4.x 安装与使用
2021-07-04
手写RPC学习笔记
K8S高可用版本部署
mySQL计算IP地址范围
上一篇文章           查看所有文章
加:2021-12-03 13:23:39  更:2021-12-03 13:26:20 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年7日历 -2024/7/6 8:31:39-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码