Java序列化心得(一):序列化设计和默认序列化格式的问题

最近在工作中指导新人开发,任务内容涉及到序列化,发现很多初学者对于序列化的概念以及使用的场景比较模糊,所以为他们总结了有关的Java Serialization的一些心得,这里记录出来与大家分享。由于关于序列化的内容很多,篇幅有限,不能全面的描述,本文只是侧重于序列化的概念以及如何设计序列化的类。如果是对序列化完全没有概念的朋友,也可以移步这里, 这是一篇优秀的介绍Java序列化的文章,相信会是开卷有益。欢迎大家留言指正。

关于自定义序列化的内容,请见Java序列化心得(二):自定义序列化

何为序列化:类对象的持久化

Java序列化接口(Serializable interface)提供框架将类的对象字节化,以二进制编码形式保存该对象的状态,并可以根据这样的字节编码复原出类的对象。

序列化的过程实际上是将一个对象“持久化”的过程:将内存中临时的Java对象固化为物理上可以存储和记录的字节形式

有的人可能会有疑问为什么要序列化?很多程序的确没有使用序列化也可以完美运行,但是有的场景中,序列化将大有作为。

想一想网络通信中,常常需要把类对象的信息从一个终端传递到网络中的另一端,对象的“状态内容”在网络中就需要以字节的形式传送,可是这些字节到了另一端改如何恢复成类对象呢?再或者是任务队列的情况下,很多任务对象要放在队列中等待被执行,但是资源有限,如果队列中内容很多,都在内存中保存有时候不现实,需要把这些任务信息保存到硬盘上,等到能够执行的时候再从硬盘中重新读取到内存而后运行。诸如以上这种需要暂时把对象的信息保存起来的情况在实际的开发中会遇到很多,这种场景中就需要序列化的帮助。

换个角度来说,JVM(Java虚拟机)在内存中创建可复用的Java对象,并维护这些对象的生命周期,即这些对象的生命周期不会比JVM的生命周期更长,只有在JVM的控制范围内,这些对象才是有效地。但在现实应用中,就可能要求指定的对象暂时离开在JVM的控制范围(如果发送到网络中或者是保存到硬盘上),并在合适的时机重新回到JVM控制范围中。Java序列化API便是为处理对象以字节形式导出/移入JVM而设计的标准接口。

序列化的代价:哪些关于序列化的头疼事:

一个类实现序列化结构很简单,只要在定义类时声明* implements Serializable*,

public class Person implements Serializable 

便可调用默认的序列化方法,生成默认的序列化格式(Default Serialization Form) ,这里需要强调两点:

  1. 序列化是保存对象的状态,既然是对象的序列化,自然只关心对象的域,而类的静态域不在序列化范围内;
  2. 在序列化对象时,不仅会序列化当前对象本身,还会对该对象引用的其它对象也进行序列化,所以要求所有在该对象序列化范围内的域都要求是可序列化的对象,这就将会出发一个迭代的过程。

虽然实现Serializable接口很简单,但决定是否要让一个类序列化却是比较头疼的事,往往不能只考虑序列化对象带来的便利,还要考虑到序列化所带来的代价,这种代价往往是因为序列化和类的继承结合在一起造成,《Effective Java》中列举了序列化的代价如下:

  1. 序列化将降低类结构的灵活性: 一旦被声明序列化,类的字节编码模式就像会成为输出API一部分,如果是默认的形式,序列化格式会反映出该类的原始内部结构,这样以来类的私有域也会成为输出API的一部分,这就破坏了信息隐藏的原则,因此要被序列化的类,其结构的设计往往要慎重;
  2. 序列化的过程可能带来Bug隐患和安全漏洞:如果代码中原来是接受一个类默认的序列化格式,但后来这个类的设计有变化,或者是这个类在被继承后子类添加了新的域,则默认序列化格式也会一起变化,此时将变化后的序列化格式传入原有代码中,就会由于序列化格式版本不一致,而造成不易被发觉的异常;
  3. 序列化将会增加新版本测试的难度:还是当序列化的类发生修改或是被继承时,序列化的版本可能有很多,为了测试代码的功能,就可能要产生多个版本的测试代码,而客户端为了接受多种序列化格式,也不得不增加冗余性。

在这里可以看出来,序列化是为了“固化”对象的信息,而继承是希望让类的对象可以多样化和动态化,二者之间在设计目标上有一定的矛盾。关于序列化和继承,有如下设计上的建议供读者参考:

  1. 基类不序列化,如果一个类是为了被广泛继承而设计的,尽量不要将其序列化,这样后患无穷,设计被序列化的类应该是结构比较固定的类;

  2. 当前的类可能不需要序列化,但是它的派生类在以后使用中不排除被序列化的可能,为了便于派生累的序列化,基类应该保留无参数的构造器,这是因为序列化的过程中,首先是要调用无参数构造器来生成类对象,其次才是往对象中填充各个域的值,如果累没有默认构造器就可能导致序列化无法进行。

  3. 定义类的序列化版本号, 来是验证接收的序列化格式和期待的序列化格式版本是否一致,其定义如下

private final static long serialVersionUID = 1L

默认情况下是根据类名、接口名、成员方法及属性等来生成一个64位的哈希字段,如果开发人员不希望通过编译来强制划分软件版本,即实现序列化接口的实体能够兼容先前版本,未作更改的类,就需要显式地定义一个名为serialVersionUID,类型为long的静态常量,只有版本号一致的类,其序列化的格式才能被相互接受,否者将会报错。有关序列化版本号的内容可以参考这里,关于版本号各种使用情况,都有详细的阐述。

默认序列化方法的问题:

因为用默认序列化格式的存在,类序列化的实现变得很轻松,但是正如上面提到的,默认的序列化格式有各种各样的短板,这些短板在特定的情况下会带来不小的麻烦,主要集中在一下几点:

  1. 默认的序列化格式将会体现类内部的格式,可能会暴露私有域;
  2. 默认序列化的过程是迭代的,这样可能会造成栈溢出;
  3. 默认序列化的过程可能消耗大量内存空间和时间;

第一点和第二点,上面的内容已经提过,这里不再多加赘述;关于第三点,默认序列化转化效率的对比,读者可以参考这篇文章,作者将GSON与之对比,结果差别十分明显。GSON不仅要向流中写入或读出数据,还需要对字符串进行词法分析,即使这样仍然比默认的序列化方式快3倍,这是因为默认的序列化过程中需要用到如反射之类的方式去取值,而且还需要处理与对象自身的一些信息。

正因为默认的序列化方式不能满足所有场景和需求,所以就需要引入定制的序列化方式(Custom Serialization Form),这部分内容将在Java序列化心得(二):自定义序列化中为大家介绍。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,607评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,047评论 2 379
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,496评论 0 335
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,405评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,400评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,479评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,883评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,535评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,743评论 1 295
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,544评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,612评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,309评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,881评论 3 306
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,891评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,136评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,783评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,316评论 2 342

推荐阅读更多精彩内容