序列化笔记

本文探讨了序列化与反序列化的概念及其代价,并详细解释了如何选择合适的序列化形式,包括默认序列化与自定义序列化。同时,介绍了readObject方法与构造方法之间的关系,以及readResolve方法的应用场景。
序列化:
将对象编码成一个字节流,以及从字节流编码中重新构造对象.
将一个对象编码成一个字节流称为序列化,相反的处理过程称为反序列化.

54:=======
实现序列化的代价:
1.一旦一个类发布,则改变这个类的灵活性将大大降低. 字节流编码变成了它的导出API的一部分.指:类自身的演变和类所在继承体系的演变(对子类序列化所加的影响).
2.它增加了错误(bug)和安全漏洞的可能性. 通常情况下对象是由构造方法来创建,序列化机制是一种语言之外的对象创建机制.
反序列化机制实际上是一个以字节流为入参的“隐藏的构造方法”, 要记住的是readObject方法和构造方法在逻辑上遵守的规则是一致的.
3.随着一个类的新版本的发行,相关的测试负担增加了.

55:====
考虑使用自定义的序列化形式:
1.若没有认真考虑默认序列化形式是否合适,则不要接受这种形式.
对于一个对象来说,理想的序列化形式应该只包含该对象所表示的逻辑数据,而逻辑数据与物理表示应该是独立的.
2.如果一个对象的物理表示等同于它的逻辑内容,则默认的序列化形式可能是合适的.如Person类,默认序列化是合理的.

3.即使你确定了默认序列化形式是合适的,通常你仍然要提供一个readObject方法以保证约束关系和安全性.
这也可以说是对入参的合法性检查. readObject要根据从字节流中获得的信息来构造对象,其本身就是一个构造方法.
4.当一个对象的物理表示与它的逻辑数据内容有实质性的区别时,使用默认序列化形式有4的问题. (类的逻辑表示表达类的一种用途,物理表示是实现逻辑表示的实现,不要让逻辑表示束缚在物理表示格式上)
4.1它使这个类的导出API永远的束缚在该类的内部表示上.
4.2它要消耗过多的空间.
4.3它要消耗过多的时间.
4.4它会引起栈溢出.

总而言之:当你决定要将一个类做成可序列化的时候,请仔细考虑应该采用什么样的序列化形式,只有当默认的序列化形式能够合理地描述状态的时候,你才使用默认的序列化形式,否则就设计一个自定义的序列化形式,通过它合理地描述对象的状态。你应该分配足够多的时间来设计一个类的序列化形式,就好像你分配足够多的时间来设计它的导出方法一样。正如你无法在将来的版本中去掉导出方法一样,你也不能去掉序列化形式中地域,它们必须被永久地保留下去,以确保序列化兼容性(serialization compalibility).选择错误的序列化形式对于一个类的复杂性和性能都会有永久的负面影响.
56。========
readObject方法与构造方法所受的约束相同.它相当于另一个公有的构造方法.不严格的说readObject 是一个"用字节流作为唯一参数"的构造方法.
当一个对象被反序列化的时候,对于客户不应该拥有的对象引用,如果哪个域包含了这样的对象引用,则必须要做保护性拷贝,这是非常重要的.(就像封装集合的作法:要么返回一个只读集合,要么返回一个保护性拷贝的集合,以保证对象内部的集合状态不会被外部修改)

57。======
必要时提供一个readResolve方法.
任何一个readResolve方法,不管是显式的还是默认的,它都会返回一个新建的实例,这个新建的实例不同于该类初始化时刻创建的实例。(一个Singleton如果实现了Serializable接口,则一定要提供一个readResolve方法,以保证在反序列化后实例仍然只有一个.)

public class Singleton implements Serializable {
private static final Singleton SINGLETON= new Singleton();
private Singleton() {}
public static Singleton getInstance() {
return SINGLETON;
}

//该方法忽略掉被反序列化的对象,简单地返回该类初始化时刻创建的那个特殊的实例.因此此类的序列化形式并不需要包含任何实际的数据;所有的实例域都应该被标记为transient.
private Object readResolve() throws IOException {
return SINGLETON;
}
}

readResolve方法不仅对于singleton对象是必要的,而且对于所有其他的实例受控的(instance-controlled)类也是必需的.另一个例子是类型安全枚举类型(typesafe enum),它的readResolve方法必须返回代表特定枚举常量的规范的实例(canonical instance).凭经验,如果你正在编写的可序列化的类没有包含公有的或者受保护的构造方法,那么请考虑它是否需要一个readResolve方法.
readResolve方法的第二个用法是,作为保护性的readObject方法的一种保守的替代选择.

readObject 是另一个构造方法,
readResolve是静态工厂方法

总而言之:无论是singleton还是instance-controlled的类,都要使用readResolve来保护"instance-control invariant"
从本质上讲,readResolve方法把readObject方法从一个事实上的公有构造方法变成一个事实上的公有静态工厂。对于那些禁止包外继承的类而言,readResovle方法作为保护性的readObject方法的一种替代选择,也是非常有用的.
(1)普通用户端(全平台) 音乐播放核心体验: 个性化首页:基于 “听歌历史 + 收藏偏好” 展示 “推荐歌单(每日 30 首)、新歌速递、相似曲风推荐”,支持按 “场景(通勤 / 学习 / 运动)” 切换推荐维度。 播放页功能:支持 “无损音质切换、倍速播放(0.5x-2.0x)、定时关闭、歌词逐句滚动”,提供 “沉浸式全屏模式”(隐藏冗余控件,突出歌词与专辑封面)。 多端同步:自动同步 “播放进度、收藏列表、歌单” 至所有登录设备(如手机暂停后,电脑端打开可继续播放)。 音乐发现与管理: 智能搜索:支持 “歌曲名 / 歌手 / 歌词片段” 搜索,提供 “模糊匹配(如输入‘晴天’联想‘周杰伦 - 晴天’)、热门搜索词推荐”,结果按 “热度 / 匹配度” 排序。 歌单管理:创建 “公开 / 私有 / 加密” 歌单,支持 “批量添加歌曲、拖拽排序、一键分享到社交平台”,系统自动生成 “歌单封面(基于歌曲风格配色)”。 音乐分类浏览:按 “曲风(流行 / 摇滚 / 古典)、语言(国语 / 英语 / 日语)、年代(80 后经典 / 2023 新歌)” 分层浏览,每个分类页展示 “TOP50 榜单”。 社交互动功能: 动态广场:查看 “关注的用户 / 音乐人发布的动态(如‘分享新歌感受’)、好友正在听的歌曲”,支持 “点赞 / 评论 / 转发”,可直接点击动态中的歌曲播放。 听歌排行:个人页展示 “本周听歌 TOP10、累计听歌时长”,平台定期生成 “全球 / 好友榜”(如 “好友中你本周听歌时长排名第 3”)。 音乐圈:加入 “特定曲风圈子(如‘古典音乐爱好者’)”,参与 “话题讨论(如‘你心中最经典的钢琴曲’)、线上歌单共创”。 (2)音乐人端(创作者中心) 作品管理: 音乐上传:支持 “无损音频(FLAC/WAV)+ 歌词文件(LRC)+ 专辑封面” 上传,填写 “歌曲信息
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值