本文详细介绍了 Android 开发中两种关键的对象序列化方式:Serializable 与 Parcelable。序列化是实现跨进程通信(IPC)和数据持久化的基础,理解两者的区别与适用场景,对于提升应用性能至关重要。Serializable 是 Java 标准库提供的通用方案,而 Parcelable 则是 Android 平台专为高性能 IPC 设计。本文将深入解析其使用方法、性能差异以及选择策略。
一、序列化基础概念
在 Android 中,当我们需要通过 Intent 和 Binder 传输复杂对象,或者需要将对象持久化到存储设备、通过网络传输时,就必须将对象转换为可以存储或传输的格式,这个过程称为序列化。其逆过程,即从序列化后的数据重建对象,称为反序列化。
简单理解,序列化就像为了运输而将房子拆解成标准化的零部件;反序列化则是到达目的地后,根据图纸重新组装房子。这两个接口正是完成“拆解”与“组装”的蓝图。
二、Serializable 接口详解
Serializable 是 Java 标准库提供的一个标记接口(一个空接口),用于声明一个类可以被序列化。
如何实现序列化?
要让一个类支持序列化非常简单,只需声明实现 Serializable 接口,并定义一个名为 serialVersionUID 的静态长整型常量即可。
import java.io.Serializable;
public class User implements Serializable {
// 序列化版本号,用于验证反序列化时类的版本一致性
private static final long serialVersionUID = 51906712373232662L;
public int userId;
public String userName;
public boolean isMale;
// 构造方法
public User(int userId, String userName, boolean isMale) {
this.userId = userId;
this.userName = userName;
this.isMale = isMale;
}
}
序列化与反序列化操作
完成类定义后,可以使用 ObjectOutputStream 和 ObjectInputStream 轻松实现对象的序列化(写入)与反序列化(读取)。
// 序列化过程:将对象写入文件
User user = new User(0, "Jack", true);
try (ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("user.txt"))) {
out.writeObject(user);
} catch (IOException e) {
e.printStackTrace();
}
// 反序列化过程:从文件读取对象
User newUser;
try (ObjectInputStream in = new ObjectInputStream(new FileInputStream("user.txt"))) {
newUser = (User) in.readObject();
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
}
理解 serialVersionUID 的重要性
serialVersionUID 是序列化机制的“版本号”。其工作机制如下:
- 序列化时:系统将当前类的
serialVersionUID 写入序列化数据。
- 反序列化时:系统会检查数据中的
serialVersionUID 是否与当前类的 serialVersionUID 一致。
- 如果一致,说明类的版本相同,反序列化成功。
- 如果不一致,意味着序列化后的类可能已被修改(如增删字段),反序列化会失败并抛出
InvalidClassException。
如果不显式声明 serialVersionUID,Java 虚拟机会根据类结构自动生成一个。一旦类发生任何改变,这个自动生成的值就会变化,导致已序列化的旧数据无法被新版本的类读取。因此,显式声明一个固定的 serialVersionUID 是保证序列化兼容性的最佳实践。
注意事项:
- 静态成员变量属于类而非对象,不参与序列化。
- 使用
transient 关键字修饰的成员变量,也会被排除在序列化过程之外。
Java 平台的序列化方案虽然通用,但其涉及大量 I/O 操作和反射,在资源受限的 Android 移动平台上开销较大。
三、Parcelable 接口详解
Parcelable 是 Android SDK 专为高性能 IPC 设计的序列化接口。它直接操作内存,避免了 Serializable 的反射和 I/O 开销,效率极高,是 Android 官方推荐的序列化方式。
如何实现 Parcelable?
在 Android Studio 中,实现 Parcelable 接口后,IDE 可以自动生成大部分模板代码,大大简化了开发过程。
-
首先,让类实现 Parcelable 接口。

-
将光标移至类名上,按 Alt + Enter,选择 “Add Parcelable implementation”,IDE 会自动生成必要的序列化代码。

-
以下是自动生成并稍作整理后的完整 Parcelable 实现代码:
import android.os.Parcel;
import android.os.Parcelable;
public class User implements Parcelable {
public int userId;
public String userName;
public boolean isMale;
// 构造方法
public User(int userId, String userName, boolean isMale) {
this.userId = userId;
this.userName = userName;
this.isMale = isMale;
}
// 从 Parcel 中反序列化对象的构造方法
protected User(Parcel in) {
userId = in.readInt();
userName = in.readString();
isMale = in.readByte() != 0;
}
// 负责反序列化的 CREATOR
public static final Creator<User> CREATOR = new Creator<User>() {
@Override
public User createFromParcel(Parcel in) {
return new User(in);
}
@Override
public User[] newArray(int size) {
return new User[size];
}
};
// 内容描述(通常返回0,若包含文件描述符则返回1)
@Override
public int describeContents() {
return 0;
}
// 序列化:将对象数据写入 Parcel
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(userId);
dest.writeString(userName);
dest.writeByte((byte) (isMale ? 1 : 0));
}
}
Parcelable 核心方法说明
| 方法 |
功能 |
常见标记位 |
writeToParcel(Parcel dest, int flags) |
将当前对象的数据写入 Parcel。 |
PARCELABLE_WRITE_RETURN_VALUE (几乎总为0) |
describeContents() |
返回对象内容的特殊描述。若无文件描述符,返回0。 |
CONTENTS_FILE_DESCRIPTOR (仅当包含文件描述符时返回1) |
Creator.createFromParcel(Parcel in) |
从 Parcel 中读取数据,构造一个新的对象。 |
- |
Creator.newArray(int size) |
创建指定大小的对象数组。 |
- |
User(Parcel in) (构造方法) |
与 createFromParcel 配合,完成对象的创建与初始化。 |
- |
四、Serializable 与 Parcelable 如何选择?
了解了两种接口的实现和原理后,如何在项目中做出选择?
-
开发效率与平台通用性
- Serializable:使用极其简单,只需声明一个接口和一个ID。它是 Java 平台标准,适合需要将对象序列化到存储设备(如文件)或通过网络传输(如RPC)到其他Java服务的场景。
- Parcelable:实现相对繁琐,但Android Studio的自动生成功能大大降低了难度。它是Android特有API,专为进程内和跨进程(AIDL)内存数据传输优化。
-
性能
- Serializable:序列化和反序列化过程开销较大,涉及大量I/O、反射和临时对象的创建,会产生可观的垃圾回收(GC)压力。
- Parcelable:性能极高。它直接在内存中进行读写操作,避免了反射和多余的I/O,是Android系统组件间(如Activity/Fragment/Services)传递数据时的首选。
-
适用场景总结
- 首选 Parcelable:在 Android 平台内进行对象传输,尤其是通过
Intent 在组件间传递、或通过 Binder 进行跨进程通信(AIDL)时,必须使用 Parcelable 以获得最佳性能。
- 使用 Serializable:当需要将对象持久化到本地文件,或序列化后通过网络传输到非Android的Java后端服务时,
Serializable 是更通用、更合适的选择。虽然也可以使用 Parcelable 完成持久化,但过程会更复杂。
核心结论:对于 Android 应用开发,在内存间传递数据优先使用高效的 Parcelable;在需要将数据写入 数据库 或文件进行长期存储,或与Java后端交互时,则可使用 Serializable。