首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

Java JSON 庫 Gson 核心用法深度解析:從入門到進階實戰

     編輯:Java 相關知識

Gson 是 Google 開源的 Java JSON 庫,以「無需註解、支援泛型、處理不可修改類」三大特性著稱。本文從核心 API、泛型處理、自定義序列化、性能優化、常見坑點五個維度,系統講解 Gson 實戰精髓。

一、核心 API 雙雄:toJson / fromJson


Gson gson = new Gson(); // 線程安全,可全局復用

// 1. 對象 -> JSON 字符串
User user = new User(1L, "張三", 25);
String json = gson.toJson(user);
// {"id":1,"name":"張三","age":25}

// 2. JSON 字符串 -> 對象
String jsonStr = "{\"id\":2,\"name\":\"李四\",\"age\":30}";
User user2 = gson.fromJson(jsonStr, User.class);

// 3. 支援 Reader/Writer 流式處理 (大數據/網絡流)
try (Reader reader = new FileReader("user.json");
     Writer writer = new FileWriter("user_out.json")) {
    User u = gson.fromJson(reader, User.class);
    gson.toJson(u, writer);
}

二、泛型處理:TypeToken 破除類型擦除

Java 泛型運行期擦除,Gson 提供 TypeToken 捕獲完整類型信息:


// List
Type userListType = new TypeToken>() {}.getType();
List users = gson.fromJson(jsonArrayStr, userListType);

// Map
Type userMapType = new TypeToken>() {}.getType();
Map userMap = gson.fromJson(jsonMapStr, userMapType);

// 巢狀泛型:Map>
Type complexType = new TypeToken>>() {}.getType();
Map> complex = gson.fromJson(jsonComplexStr, complexType);

原理:匿名內部類繼承 TypeToken,通過 getGenericSuperclass() 獲取 ParameterizedType,保留泛型參數。

三、自定義序列化/反序列化:適配器模式

1. JsonSerializer / JsonDeserializer


// LocalDate 適配器 (Gson 默認不支援 java.time)
public class LocalDateAdapter implements JsonSerializer, JsonDeserializer {
    private static final DateTimeFormatter FMT = DateTimeFormatter.ISO_LOCAL_DATE;
    
    @Override public JsonElement serialize(LocalDate src, Type typeOfSrc, JsonSerializationContext context) {
        return new JsonPrimitive(src.format(FMT));
    }
    @Override public LocalDate deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) 
            throws JsonParseException {
        return LocalDate.parse(json.getAsString(), FMT);
    }
}

// 註冊
Gson gson = new GsonBuilder()
    .registerTypeAdapter(LocalDate.class, new LocalDateAdapter())
    .create();

2. TypeAdapter (流式、高性能、更底層)


public class UserTypeAdapter extends TypeAdapter {
    @Override public void write(JsonWriter out, User value) throws IOException {
        out.beginObject();
        out.name("id").value(value.getId());
        out.name("name").value(value.getName());
        out.name("age").value(value.getAge());
        out.endObject();
    }
    @Override public User read(JsonReader in) throws IOException {
        Long id = null; String name = null; Integer age = null;
        in.beginObject();
        while (in.hasNext()) {
            switch (in.nextName()) {
                case "id": id = in.nextLong(); break;
                case "name": name = in.nextString(); break;
                case "age": age = in.nextInt(); break;
                default: in.skipValue();
            }
        }
        in.endObject();
        return new User(id, name, age);
    }
}

// 註冊 (nullSafe 可選)
Gson gson = new GsonBuilder()
    .registerTypeAdapter(User.class, new UserTypeAdapter().nullSafe())
    .create();

四、GsonBuilder 進階配置


Gson gson = new GsonBuilder()
    // 格式化輸出 (調試用)
    .setPrettyPrinting()
    // null 字段輸出 (默認忽略)
    .serializeNulls()
    // 日期格式化 (適用 Date/Calendar,java.time 需適配器)
    .setDateFormat("yyyy-MM-dd HH:mm:ss")
    // 字段命名策略 (駝峰 -> 下劃線)
    .setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES)
    // 排除字段 (多種方式)
    .addSerializationExclusionStrategy(new ExclusionStrategy() {
        @Override public boolean shouldSkipField(FieldAttributes f) {
            return f.getAnnotation(Transient.class) != null; // @Transient 忽略
        }
        @Override public boolean shouldSkipClass(Class clazz) { return false; }
    })
    // 版本控制
    .setVersion(1.0)
    // 禁用 HTML 轉義 (默認轉義 < > & 等)
    .disableHtmlEscaping()
    // 允許單引號、註釋等非標準 JSON (寬鬆模式)
    .setLenient()
    .create();

五、實戰場景與避坑指南

場景/坑點 問題現象 解決方案
java.time 類型 (LocalDate 等) 序列化為對象而非字符串 註冊 TypeAdapter / 使用 gson-javatime-adapters
循環引用 (A->B->A) StackOverflowError @Expose 只序列化單向 / 自定義 TypeAdapter 打破循環 / 使用 @Since 版本控制
字段名不一致 (camelCase vs snake_case) 反序列化字段為 null @SerializedName("user_name") 或 setFieldNamingPolicy
數值精度丟失 (Long -> JS Number) JS 端 Long 變不精確 Long 序列化為 String: new TypeAdapter() { write -> out.value(String.valueOf(v)) }
大 JSON 內存溢出 OOM 流式處理: gson.fromJson(reader, Type) / JsonReader 手動解析
Map 鍵非 String 鍵變為對象字符串 enableComplexMapKeySerialization() (輸出 {"keyObj":val})
忽略未知字段 (兼容性) 默認忽略,安全 無需配置,Gson 默認寬容未知字段
單例 Gson 實例 重複創建浪費資源 全局單例或 DI 容器管理,Gson 線程安全

六、性能優化建議

  1. 復用 Gson 實例:Gson 線程安全,創建開銷大 (反射掃描),應用全局單例。
  2. 優先 TypeAdapter 而非 JsonSerializer:流式 API 避免中間 JsonElement 對象創建,序列化/反序列化快 2-5 倍。
  3. 避免 setPrettyPrinting() 生產環境:增加 30-50% 體積與 CPU 開銷。
  4. 大數據場景用流式 API:JsonReader/JsonWriter 逐 token 處理,常駐內存極低。
  5. 關閉 HTML 轉義:disableHtmlEscaping() 微幅提升性能 (前提是確信輸出不含 XSS 風險)。

七、Gson vs Jackson vs Fastjson 選型

維度 Gson Jackson Fastjson
易用性 ⭐⭐⭐⭐⭐ 簡潔 ⭐⭐⭐ 功能豐富但複雜 ⭐⭐⭐⭐ API 簡單
性能 優秀 極致 (後端首選) 極致 (曾有安全漏洞)
泛型支援 原生 TypeToken TypeReference TypeReference
java.time 支援 需適配器 內建模塊 內建支援
流式 API TypeAdapter/JsonReader JsonParser/JsonGenerator JSONReader/JSONWriter
Spring Boot 默認 可切換 默認 不建議
推薦場景 Android、中小項目、簡單需求 企業級後端、高性能、複雜序列化 舊項目維護、特定場景

八、總結

  • 核心雙雄:toJson(obj) / fromJson(json, Type) 覆蓋 90% 場景。
  • 泛型關鍵:new TypeToken<List<User>>(){}.getType() 破除類型擦除。
  • 擴展點:TypeAdapter (高性能流式) > JsonSerializer/Deserializer (簡便樹模型)。
  • 配置入口:GsonBuilder 鏈式配置格式化、命名策略、null處理、版本、適配器註冊。
  • 最佳實踐:單例 Gson、註冊 java.time 適配器、Long 輸出 String、生產環境關閉 pretty print、大數據用流式。

Gson 以「簡單、直觀、無侵入」贏得廣大開發者青睞。掌握 TypeToken 與 TypeAdapter 兩大殺手鐧,即可應對 99% 的 JSON 處理場景。對於高性能、複雜序列化需求的企業級後端,Jackson 仍是首選;但對於 Android、中小型項目、快速原型開發,Gson 是性價比最高的選擇。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved