当前位置: 首页 > 科技观察

面试官:详细说说你对序列化的理解

时间:2023-03-21 22:54:35 科技观察

采访者:请详细谈谈您对连载的理解。转载本文,请联系LoveSmile的架构师公众号。我们必须问为什么。在解释序列化的概念和原理之前,我们先来了解一下为什么需要序列化。为什么要序列化?如果只看定义的话,我觉得你很难一下子理解序列化的含义,所以我们可以从另一个角度来感受什么是序列化。你玩过这个游戏吗?玩过的同学应该都知道,游戏中有一个叫做“保存”的功能。每次不想玩的时候,都可以保存当前进度。下次有空玩的时候直接载入存档即可。然后玩,这样做的好处是之前的游戏进度不会丢失,如果每次打开都重新玩,估计大家会没耐心的。如果将面向对象的思想带到游戏世界中,在我们眼中,无论是游戏角色还是游戏中的怪物、装备等都可以看作是每一个对象:角色对象(包括性别、等级、经验创建一个游戏角色在玩游戏的过程中就像是创建了一个角色对象,得到一套装备就像是创建了一个装备对象,路上遇到的怪物等等也是对象。我们再用计算机的思维来思考一下。创建的对象都存储在内存中。大家都知道,内存中的数据保存时间很短,断电后就会消失。但是,手动保存游戏后,即使关闭了天啊,再次进入游戏读取存档时,会发现游戏中创建的角色和装备还在。这很奇怪。显然,内存中的数据会在断电后消失。为什么?稍微想想你知道的,我们在归档过程中将内存中的数据存储到电脑的硬盘中。断电后硬盘上的数据不会丢失(不用担心,硬盘损坏不考虑数据丢失)。这个过程就是对象的持久化,也就是我们今天要说的对象序列化。对象序列化的逆过程称为反序列化,反序列化也很好理解为从硬盘读取信息形成对象。什么是序列化?前面介绍的游戏例子就是为了让大家形象的理解什么是序列化和反序列化。简单概括就是:序列化是指将对象实例的状态保存到存储介质中的过程。反序列化是指将存储在存储介质中的对象的状态转换为对象的过程。用一个更抽象的概念来说:序列反序列化:将一个对象转换成可传输的字节序列的过程平台和网络传输,而我们进行跨平台存储和网络传输的方式是IO,IO支持的数据格式是字节数组。现在的问题是如何将对象转换成字节数组?这很容易做到,一般的编程语言都有这种能力,可以很方便地将一个对象转换成字节数组。仔细想想,我们单方面把对象转成字节数组是不行的,因为没有正规的字节数组,我们是没有办法恢复对象原来的样子的。简单来说,很容易将对象转换成字节数组。将字节数组还原为对象是比较困难的,所以我们必须在将对象转换为字节数组时制定一个规则(序列化),然后在从IO流中读取数据时使用这个规则将对象还原(反序列化)。还是拿上面的游戏为例,我们把正在玩的游戏存到硬盘上,序列化就是把角色对象和装备对象一个一个存到硬盘上,然后留下一张原对象的结构图,以及反序列化是将字符对象和设备对象存储在硬盘中。实物根据图纸一一复原。常见的序列化方式序列化只是定义了拆解对象的具体规则,而这些规则必须是多样的。比如现在常见的序列化方式有:JDKnative、JSON、ProtoBuf、Hessian、Kryo等。(1)JDKNative作为一种成熟的编程语言,JDK有自己的序列化方式。只要该类实现了Serializable接口,就可以通过ObjectOutputStream类将对象转换为byte[]字节数组。JDK序列化会将对象类的描述信息以及所有的属性和继承的元数据序列化成一个字节流,所以生成的字节流会比较大。另外,这种序列化方式是JDK自带的,所以不支持跨语言。简单总结一下:JDK原生的序列化方式产生的字节流比较大,而且不支持跨语言,所以在实际项目和框架中很少使用。(2)ProtoBuf,由Google推出,是一种语言无关、平台无关、可扩展的结构化数据序列化方法,可用于通信协议、数据存储等,序列化后体积小,可扩展一般用于对传输性能要求较高的系统中。(4)HessianHessian是一种轻量级的二进制web服务协议,主要用于传输二进制数据。Hessian支持在传输数据之前将对象序列化为二进制流。与JDK原生序列化相比,Hessian序列化体积更小,性能更好。(5)KryoKryo是一个Java序列化框架,号称Java中最快的序列化框架。Kryo在序列化速度上有优势,底层依赖字节码生成机制。由于只能限于JVM语言,Kryo不支持跨语言使用。(6)上面提到的JSON中的几种序列化方法,都是将对象直接转化为二进制,即byte[]字节数组,这些方法都可以称为二进制方法。JSON序列化方式生成一串正则字符串,在可读性上优于上述方式,但在体积上没有优势。另外,JSON是一个常规的字符串,不绑定任何编程语言,自然是跨平台的。总结一下:JSON可读性强,支持跨平台,体积略小。常见的JSON序列化框架有:fastJSON、Jackson、Gson等。序列化技术的选择上面列出的序列化技术各有优缺点。不能简单的说哪个最好,不然也不会有那么多的序列化技术并存。既然有这么多的序列化技术可供选择,那么在实际项目中如何选择类型呢?我觉得需要结合具体的项目,比较技术是针对业务的。可以考虑以下几个因素:(1)协议是否支持跨平台如果一个大系统有多种语言混合开发,那么肯定不适合有语言限制的序列化协议,比如JDKnative,Kryo这些只能在Java语言范围内使用。你可以用JDK原生的方式序列化,不能用其他语言反序列化。(2)序列化速度如果序列化频率非常高,那么选择一个序列化速度快的协议将大大提高你的系统性能。(3)如果序列化产生的数据量在网络中频繁传输,则数据越小越好。小数据传输速度更快,不占用带宽,还可以提高整个系统的性能。因此,序列化生成的大小很重要。总结(1)为什么要序列化?因为我们需要将内存中的对象存储到介质中,或者我们需要将一个对象通过网络传输到另一个系统中。(2)什么是序列化?序列化是将对象转换为可传输的字节序列的过程;反序列化是将字节序列恢复到对象的过程。(3)序列化机制序列化的最终目的是实现对象的跨平台存储和网络传输,而我们实现跨平台存储和网络传输的方法是IO,IO支持的数据格式是bytearray。在将对象转换为字节数组时,需要制定一个规则,这就是序列化机制。(4)常见的序列化方式现在常见的序列化方式有:JDKnative、JSON、ProtoBuf、Hessian、Kryo等。(5)序列化技术的选择序列化技术的选择最重要的就是考虑这三个方面:协议是否支持跨平台,序列化速度,序列化产生的体积。