序列化的作用及其两种序列化方式的区别
序列化作用:
序列化(Serialization) 是将 对象的状态(字段值)转换为可存储或传输的字节序列 的过程;反序列化(Deserialization) 则是将字节序列恢复为对象的过程。其核心作用包括:
- 数据持久化存储
- 将对象状态保存到 文件、数据库或缓存 中,以便程序重启后恢复数据。
- 例如:用户配置信息、游戏进度、临时缓存数据等。
- 跨进程 / 跨网络通信
- 在分布式系统中,对象需通过网络传输(如 HTTP、RPC 协议),或在 Android 中通过
Intent
、Binder
跨进程传递数据。 - 此时需将对象序列化为字节流,经网络传输后再反序列化为目标对象。
- 在分布式系统中,对象需通过网络传输(如 HTTP、RPC 协议),或在 Android 中通过
- 数据格式转换
- 将复杂对象转换为 JSON、XML 等通用格式,便于与其他系统或服务交互(如 API 接口返回数据)。
- 状态传递与恢复
- 在 Android 中,Activity 被销毁重建时,通过
onSaveInstanceState
序列化临时状态(如文本框内容),重建后反序列化恢复。 - 在 Java Web 中,
HttpSession
存储的对象需实现序列化,以便在服务器集群间复制或持久化。
- 在 Android 中,Activity 被销毁重建时,通过
应用场景详解
- 本地数据存储
-
场景:
- 保存用户设置(如主题模式、音量偏好)到文件(如 Android 的
SharedPreferences
本质通过XML
序列化)。 - 缓存网络请求结果到本地(如图片、JSON 数据),减少重复请求。
- 保存用户设置(如主题模式、音量偏好)到文件(如 Android 的
-
技术实现:
-
Java:通过
ObjectOutputStream
将对象写入文件(需实现Serializable
)。 -
Android:使用
Parcelable
或Serializable
配合SharedPreferences
、Room
数据库。 -
示例代码(Java 序列化到文件):
FileOutputStream fileOut = new FileOutputStream("user.dat"); ObjectOutputStream out = new ObjectOutputStream(fileOut); out.writeObject(user); // 序列化对象 out.close();
-
- 网络传输与跨进程通信
-
场景:
- 分布式系统:微服务间通过 RPC(如 gRPC、Dubbo)传递对象,需将对象序列化为二进制格式(如 Protobuf、JSON)。
- Android 跨进程通信(IPC):通过
Binder
机制传递自定义对象(需实现Parcelable
)。 - 前端与后端交互:后端将 Java 对象序列化为 JSON 返回给前端(如 Spring MVC 自动将对象转为 JSON)。
-
关键技术:
-
序列化协议:JSON(可读性强)、Protobuf(高效二进制)、XML(已逐渐被替代)。
-
Android 示例:
Intent intent = new Intent(this, TargetActivity.class); intent.putExtra("user", user); // user 需实现 Parcelable startActivity(intent);
-
- 框架与中间件的数据传递
-
场景:
- Android 的
ViewModel
组件通过onSaveInstanceState
序列化数据,防止屏幕旋转时数据丢失。 - 消息队列(如 Kafka、RabbitMQ)传递对象时,需将消息序列化(如使用 Avro、JSON 格式)。
- Android 的
-
典型案例:
class MainViewModel : ViewModel() { private val _user = MutableLiveData<User>() val user: LiveData<User> get() = _user }
若User未序列化,屏幕旋转时ViewModel可能无法正确恢复数据。
Parcelable与Serializable 的性能比较
首先Parcelable 的性能要强于Serializable 的原因
(1)在内存的使用中,前者在性能方面要强于后者;
(2)后者在序列化操作的时候会产生大量的临时变量,(原因是使用了反射机制) 从而导致GC的频繁调用,因此在性能上会稍微逊色;
(3)Parcelable是以binder作为信息载体的,在内存上的开销比较小,因此在内存之间进行数据传递的时候,Android推荐使用Parcelable,既然是内存方面比价有优势,那么自然就要优先选择;
(4)在读写数据的时候,Parcelable是在内存中直接进行读写,而Serializable是 通过使用IO流的形式将数据读写入在硬盘上;
但是:虽然Parcelable 的性能要强于Serializable,但是仍然有特殊的情况需要使用 Serializable,而不去使用Parcelable,因为Parcelable无法将数据进行持久化,因此 在将数据保存在磁盘的时候,仍然需要使用后者,因为前者无法很好的将数据进行 持久化,(原因是在不同的Android版本当中,Parcelable可能会不同,因此数据的持 久化方面仍然是使用Serializable
总结:Java应用程序中有Serializable来实现序列化操作,Android中有Parcelable来 实现序列化操作,相关的性能也作出了比较,因此在Android中除了对数据持久化的时候需要使用到Serializable来实现序列化操作,其他的时候我们仍然需要使用Parcelable来实现序列化操作,因为在Android中效率并不是最重要的,而是内存。
binder的Parcel默认用哪种序列化
- 性能优先
Parcelable
是 Android 专为跨进程通信(IPC)设计的序列化接口,通过手动实现writeToParcel
和createFromParcel
方法,避免了反射开销,效率远高于Serializable
(后者基于 Java 反射,性能较差)。
在 Binder 通信中,数据需频繁跨进程传输,Parcelable
的高性能特性成为默认选择。 - Parcel 底层支持
Parcel
提供了专用方法读写Parcelable
对象:writeParcelable(Parcelable value, int flags)
readParcelable(ClassLoader loader)
而对于Serializable
,需通过通用方法writeSerializable(Object value)
和readSerializable()
处理,并非默认首选。
- Binder 强制要求
当通过 Binder 传递自定义对象时,必须实现Parcelable
(否则会抛出AndroidRuntimeException
),这进一步确立了Parcelable
在 Binder 通信中的默认地位。