Java中的序列化和反序列化使用及解讀
更新時間:2026年02月17日 11:37:16 作者:晚夜微雨問海棠呀
文章總結了Java中序列化和反序列化的概念,包括序列化的用途、實現方式和注意事項,此外,還介紹了其他幾種常見的序列化框架,如JSON序列化、ProtocolBuffers和Kryo,并給出了最佳實踐和使用場景建議
基本概念
序列化(Serialization):將對象的狀態(tài)信息轉換為可以存儲或傳輸的形式(如字節(jié)流)的過程。
反序列化(Deserialization):從字節(jié)流中恢復對象的過程,是序列化的逆操作。
為什么需要序列化?
- 持久化存儲:將對象保存到文件或數據庫中
- 網絡傳輸:在網絡上傳輸對象(如分布式系統(tǒng)、RPC調用)
- 進程間通信:在不同進程之間傳遞對象
- 緩存:將對象緩存到內存或磁盤
Java 序列化實現
1. 實現 Serializable 接口
import java.io.*;
// 可序列化的類
public class Person implements Serializable {
// 序列化版本號(強烈建議)
private static final long serialVersionUID = 1L;
private String name;
private int age;
// transient 關鍵字:該字段不會被序列化
private transient String password;
public Person(String name, int age, String password) {
this.name = name;
this.age = age;
this.password = password;
}
// getters and setters...
@Override
public String toString() {
return "Person{name='" + name + "', age=" + age + ", password='" + password + "'}";
}
}
2. 序列化操作
public class SerializationDemo {
public static void serialize(Object obj, String filename) throws IOException {
try (ObjectOutputStream oos = new ObjectOutputStream(
new FileOutputStream(filename))) {
oos.writeObject(obj);
System.out.println("對象序列化成功!");
}
}
public static Object deserialize(String filename) throws IOException, ClassNotFoundException {
try (ObjectInputStream ois = new ObjectInputStream(
new FileInputStream(filename))) {
Object obj = ois.readObject();
System.out.println("對象反序列化成功!");
return obj;
}
}
public static void main(String[] args) {
Person person = new Person("張三", 25, "123456");
try {
// 序列化
serialize(person, "person.ser");
// 反序列化
Person deserializedPerson = (Person) deserialize("person.ser");
System.out.println("反序列化后的對象: " + deserializedPerson);
// 輸出: Person{name='張三', age=25, password='null'} (password為null因為transient)
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
}
}
}
重要概念
1. serialVersionUID
private static final long serialVersionUID = 1L;
- 用于標識類的版本
- 如果類結構發(fā)生變化,serialVersionUID 也應改變
- 如果不指定,JVM 會自動生成,但可能導致反序列化失敗
2. transient 關鍵字
private transient String password; // 不會被序列化
標記不需要序列化的字段,如:
- 敏感信息(密碼)
- 臨時數據
- 可重新計算的數據
3. 自定義序列化
public class CustomPerson implements Serializable {
private String name;
private int age;
// 自定義序列化方法
private void writeObject(ObjectOutputStream oos) throws IOException {
oos.defaultWriteObject(); // 默認序列化
// 可以添加額外的序列化邏輯
}
// 自定義反序列化方法
private void readObject(ObjectInputStream ois)
throws IOException, ClassNotFoundException {
ois.defaultReadObject(); // 默認反序列化
// 可以添加額外的反序列化邏輯
}
}
4. Externalizable 接口
import java.io.*;
public class ExternalizablePerson implements Externalizable {
private String name;
private int age;
// 必須有無參構造器
public ExternalizablePerson() {}
public ExternalizablePerson(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public void writeExternal(ObjectOutput out) throws IOException {
out.writeObject(name);
out.writeInt(age);
}
@Override
public void readExternal(ObjectInput in)
throws IOException, ClassNotFoundException {
name = (String) in.readObject();
age = in.readInt();
}
}
序列化的注意事項
安全問題
// 反序列化可能存在安全風險 Object obj = ois.readObject(); // 可能執(zhí)行惡意代碼
- 反序列化不受信任的數據可能導致代碼執(zhí)行
- 建議使用白名單驗證類
- 考慮使用安全的序列化框架
性能問題
- Java 原生序列化性能較差
- 生成的字節(jié)流較大
- 考慮使用其他序列化框架
其他序列化框架
1. JSON 序列化(Jackson)
import com.fasterxml.jackson.databind.ObjectMapper; ObjectMapper mapper = new ObjectMapper(); // 序列化為 JSON String json = mapper.writeValueAsString(person); // 從 JSON 反序列化 Person person = mapper.readValue(json, Person.class);
2. Protocol Buffers
// 需要定義 .proto 文件 // 高性能、跨語言、體積小
3. 其他框架
- Gson:Google 的 JSON 庫
- Fastjson:阿里巴巴的 JSON 庫
- Kryo:高性能二進制序列化
- Hessian:二進制序列化協(xié)議
最佳實踐
- 始終聲明 serialVersionUID
- 使用 transient 保護敏感數據
- 考慮使用 JSON 等文本格式替代二進制序列化
- 反序列化時進行數據驗證
- 對于性能敏感場景,使用專業(yè)序列化框架
- 避免序列化不可信的數據
- 不要序列化包含資源(如文件句柄、數據庫連接)的對象
總結
| 特性 | Java 原生序列化 | JSON 序列化 | Protocol Buffers |
|---|---|---|---|
| 可讀性 | 二進制 | 文本 | 二進制 |
| 性能 | 一般 | 較慢 | 很快 |
| 跨語言 | 僅 Java | 支持 | 支持 |
| 體積 | 較大 | 較大 | 很小 |
| 使用場景 | Java 內部使用 | Web API | 高性能場景 |
選擇合適的序列化方式取決于具體的使用場景、性能要求和跨語言需求。
以上為個人經驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關文章
使用java8 API遍歷過濾文件目錄及子目錄和隱藏文件示例詳解
這篇文章主要介紹了使用java8API遍歷過濾文件目錄及子目錄及隱藏文件示例詳解,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2020-07-07
Java中ThreadLocal使用原理及Synchronized區(qū)別
ThreadLocal叫做線程變量,本文詳細的介紹了ThreadLocal使用原理及Synchronized區(qū)別,有需要的朋友可以參考一下,希望對你有所幫助。2023-05-05
spring cloud oauth2 feign 遇到的坑及解決
這篇文章主要介紹了spring cloud oauth2 feign 遇到的坑及解決方案,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-03-03
Spring Boot結成MyBatis-Plus最全配置指南
本文主要介紹了Spring Boot結成MyBatis-Plus最全配置指南,包括依賴引入、配置數據源、Mapper 掃描、基本CRUD操作等,具有一定的參考價值,感興趣的可以了解一下2025-03-03

