在 Android 开发中,data class
、Serializable
和 Parcelable
是三种常见的对象处理方式,它们有各自的用途和特点。以下是它们的区别:
1. data class
data class 是 Kotlin 提供的一种特殊的类,用于简化数据模型类的声明。
特点:
- 用于表示数据模型,自动生成常见的方法(
toString()
、equals()
、hashCode()
、copy()
等)。 - 不提供默认的序列化或反序列化功能,需要与其他机制(如
Parcelable
或Serializable
)结合使用。
优点:简洁,减少样板代码。易于比较和拷贝数据对象。
缺点:仅是一个基础结构,不支持直接跨进程传输或持久化。
2. Serializable
Serializable
是 Java 提供的一种序列化接口,用于将对象转换为字节流,以便存储或跨进程传输。
特点:
- 实现序列化很简单,只需让类实现
Serializable
接口。 - Java 自带,无需额外依赖。
- 使用反射机制进行序列化和反序列化。
- 易于实现,代码简单。
- 支持 Java 的所有对象。
性能较差:使用反射机制,效率低,序列化的内存开销大。生成的字节流较大,不适合 Android 中的高性能场景。
3. Parcelable
Parcelable是 Android 提供的一种高效的序列化方式,专为在 Android 中使用而设计,常用于在组件间传递对象(如通过 Intent
)。
特点:
- 通过手动实现
Parcelable
接口来控制序列化和反序列化。 - 基于写入和读取方法,无反射,效率高。
优点:
- 性能高:更适合 Android 中的高频序列化场景。
- 更灵活,可自定义序列化逻辑。
缺点:
- 实现较复杂:需要手动实现
writeToParcel()
和CREATOR
。
例子:
4.性能对比
特性 | data class | Serializable | Parcelable |
---|---|---|---|
实现难度 | 简单 | 简单 | 较复杂(但可用 @Parcelize 简化) |
性能 | 不涉及序列化 | 差(反射机制,开销大) | 高(无反射,开销小) |
使用场景 | 数据模型 | 持久化或跨进程传输(非高频) | Android 中的高频数据传输 |
序列化效率 | 无 | 较低 | 高 |
对象大小 | 无 | 较大 | 较小 |
跨平台 | 无限制 | 跨平台支持 | Android 特定 |
5.选择建议
- 只用于数据模型:选择
data class
,代码更简洁。 - 需要跨进程传输但性能要求不高:选择
Serializable
,实现简单。 - 需要高效的序列化和数据传输:选择
Parcelable
,特别适用于 Android 中的Intent
和Bundle
。
6. 什么是序列化(Serialization)?
序列化是将对象的状态(属性数据)转换为字节流或其他可存储或传输的格式的过程。
主要作用:
- 存储:将对象保存到文件或数据库中。
- 传输:在网络中传输对象,比如在客户端与服务器之间传递数据。
- 缓存:将对象转化为可恢复的格式,便于后续恢复使用。
data class User(val id: Int, val name: String)
序列化后
Byte stream: [0x00, 0x01, 0x02, ...]
7. 什么是反序列化(Deserialization)?
反序列化是将序列化后的字节流(或存储格式)重新转换回原始对象的过程。
主要作用:
- 从存储或传输的格式中重建对象。
- 恢复数据到应用中,便于程序继续使用。
8.序列化与反序列化的用途
- 网络传输:客户端与服务器通过网络传输对象时,数据必须是字节流。序列化将对象转为字节流发送,接收端通过反序列化恢复对象。
- 持久化存储:将对象存储到文件、数据库等位置,便于稍后加载。
- 跨进程通信(IPC):Android 的
Binder
机制通过序列化对象实现不同组件间的数据传递。 - 缓存数据:将对象保存到内存或磁盘中,通过反序列化快速恢复。
在 Android 中:
- Parcelable:Android 提供的高效序列化接口,专为高性能和内存敏感场景设计
@Parcelize
data class User(val id: Int, val name: String) : Parcelable
在 Java 中:
- Serializable 接口:对象通过实现此接口进行序列化。
其他方式:通过Gson,Moshi等三方库实现
示例代码
Serializable 示例
// 序列化
ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("user.ser"));
User user = new User(1, "Alice");
out.writeObject(user);
// 反序列化
ObjectInputStream in = new ObjectInputStream(new FileInputStream("user.ser"));
User user = (User) in.readObject();
System.out.println(user.getName());
Parcelable 示例
@Parcelize
data class User(val id: Int, val name: String) : Parcelable
// Intent 传递对象
val intent = Intent(this, DetailActivity::class.java)
intent.putExtra("user", user) // 序列化
startActivity(intent)
// 在目标 Activity 中获取对象
val user = intent.getParcelableExtra<User>("user") // 反序列化
疑问:
data class不具有序列化的性质,那为何在使用网络请求时,并没有对其进行特殊处理?
答:因为Retrofit 这样的网络框架,这些框架自动处理了 data class
的序列化和反序列化。这并不是因为 data class
自身具有序列化的性质,而是因为 网络库(如 Gson 或 Moshi)为其提供了支持。
- 发送请求时:Retrofit 会将你的
data class
对象序列化为 JSON。 - 接收响应时:Retrofit 会通过 JSON 库将服务器返回的 JSON 反序列化为你的
data class
对象。
tips:
在创建实体类时,@Keep
注解是非常明智的,这能防止代码混淆(ProGuard/R8)时移除或重命名你的数据类字段,确保使用Gson时可以正确地进行序列化和反序列化。