大家好,我是 V 哥。Jackson和Gson是Java中最常用的兩個JSON_blnk解析庫,它們在解析速度、靈活性、序列化/反序列化能力上各有特點(diǎn)。下面V 哥從功能特性、性能、源碼實(shí)現(xiàn)等方面對比它們的優(yōu)缺點(diǎn)。
@JsonProperty
、@JsonIgnore
等)。@SerializedName
)。TypeToken
來實(shí)現(xiàn)復(fù)雜類型的反序列化。一般來說,Jackson的性能優(yōu)于Gson,尤其是在處理大數(shù)據(jù)量和復(fù)雜對象時,Jackson表現(xiàn)更佳。這主要?dú)w因于Jackson內(nèi)部的高效流式解析器和緩存機(jī)制,它避免了內(nèi)存中的大量臨時對象創(chuàng)建,提升了處理速度。
Jackson的流式API(如JsonParser
和JsonGenerator
)提供了細(xì)粒度的數(shù)據(jù)處理,適合在性能要求較高的場景使用。Gson則使用內(nèi)存樹模型處理JSON,這在內(nèi)存開銷和解析速度上較劣勢。
接下來,V 哥通過分析兩個組件的核心源碼實(shí)現(xiàn),來看一下兩者的不同之處。
Jackson實(shí)現(xiàn)基于三個核心模塊:jackson-core
、jackson-databind
和jackson-annotations
。
jackson-core
中實(shí)現(xiàn)了高效的流式解析器JsonParser
和生成器JsonGenerator
。這些解析器可以在讀取和寫入時逐行處理數(shù)據(jù),避免不必要的對象創(chuàng)建,減少內(nèi)存使用。jackson-databind
負(fù)責(zé)對象-JSON之間的轉(zhuǎn)換,通過反射和注解處理。Module
接口定義和動態(tài)注入,實(shí)現(xiàn)了靈活的格式支持。下面V哥通過源碼分析來具體介紹:
Jackson 的源碼實(shí)現(xiàn)涉及多個模塊(如 jackson-core
、jackson-databind
、jackson-annotations
等),我們可以從 Jackson 的數(shù)據(jù)解析與生成的基本流程、數(shù)據(jù)綁定模塊的實(shí)現(xiàn)、注解處理的方式、流式 API 等方面逐步分析其源碼。
Jackson 使用了流式解析器 JsonParser
和生成器 JsonGenerator
,這使得它在處理大數(shù)據(jù)量 JSON 時具有較好的性能。jackson-core
模塊提供了這兩個主要類。Jackson 的流式 API 是逐字節(jié)處理 JSON 數(shù)據(jù)的,因此可以實(shí)現(xiàn)低內(nèi)存消耗和高效的數(shù)據(jù)處理。
在 jackson-core
的 JsonParser
類中,實(shí)現(xiàn)了對 JSON 數(shù)據(jù)的逐步解析。它采用“令牌(Token)”的形式進(jìn)行解析,常見的 Token 包括 START_OBJECT
、FIELD_NAME
、VALUE_STRING
等。
JsonParser
類的核心方法 nextToken()
:
switch-case
結(jié)構(gòu),處理 JSON 字符串中的各類數(shù)據(jù)。"{"
會生成 START_OBJECT
,而 "}"
會對應(yīng) END_OBJECT
。public JsonToken nextToken() throws IOException {
// 實(shí)現(xiàn)不同字符的判斷邏輯,根據(jù) JSON 數(shù)據(jù)逐步解析
int ch = nextByte();
switch (ch) {
case '{':
_currToken = JsonToken.START_OBJECT;
return _currToken;
case '}':
_currToken = JsonToken.END_OBJECT;
return _currToken;
// 省略其他分支
}
}
JsonGenerator
類則用于寫入 JSON,它將數(shù)據(jù)以 Token 的形式逐步生成,適用于輸出大文件場景。public void writeStartObject() throws IOException {
_writeContext.writeStartObject();
_generator.writeStartObject();
}
Jackson 的 jackson-databind
模塊負(fù)責(zé)對象和 JSON 之間的自動映射和綁定。核心實(shí)現(xiàn)類是 ObjectMapper
,它通過反射技術(shù)將 JSON 字段自動映射到 Java 對象字段。
ObjectMapper
中主要通過 readValue()
和 writeValue()
方法來實(shí)現(xiàn) JSON 與對象的互轉(zhuǎn)。
readValue()
方法用于將 JSON 轉(zhuǎn)換為對象。通過 DeserializationContext
和 JsonDeserializer
的配合,它能夠解析復(fù)雜的 JSON 數(shù)據(jù)到 Java 對象。public <T> T readValue(JsonParser p, Class<T> valueType) throws IOException {
JavaType javaType = _typeFactory.constructType(valueType);
JsonDeserializer<Object> deser = _findRootDeserializer(_config, javaType);
return (T) deser.deserialize(p, _deserializationContext);
}
writeValue()
方法用于將對象轉(zhuǎn)換為 JSON 字符串。它會先通過 SerializationContext
和 JsonSerializer
獲取到需要的 JSON 結(jié)構(gòu),然后通過 JsonGenerator
寫入。public void writeValue(JsonGenerator gen, Object value) throws IOException {
JsonSerializer<Object> serializer = _serializerProvider().findTypedValueSerializer(value.getClass(), true, null);
serializer.serialize(value, gen, _serializerProvider());
}
Jackson 支持豐富的注解,例如 @JsonProperty
、@JsonIgnore
等,用于精細(xì)控制序列化和反序列化的過程。注解的處理主要依賴 AnnotationIntrospector
和 BeanSerializerFactory
等類。
在 Jackson 中,@JsonProperty
注解通過 AnnotationIntrospector
的 findPropertyNameForParam()
方法來獲取指定的字段名,并對 Java 字段進(jìn)行映射。
AnnotationIntrospector
類中會檢查字段上是否存在 Jackson 注解,如果存在則執(zhí)行注解對應(yīng)的序列化規(guī)則。public String findPropertyNameForParam(AnnotatedParameter param) {
JsonProperty ann = param.getAnnotation(JsonProperty.class);
return (ann == null) ? null : ann.value();
}
BeanSerializerFactory
類會解析所有字段和注解的關(guān)聯(lián)關(guān)系,并生成一個 BeanSerializer
對象,用于在序列化時將注解信息加入。public JsonSerializer<Object> createBeanSerializer(SerializerProvider prov, JavaType type, BeanDescription beanDesc) {
BeanSerializerBuilder builder = constructBeanSerializerBuilder(beanDesc);
List<BeanPropertyWriter> props = findBeanProperties(prov, beanDesc, builder);
builder.setProperties(props);
return builder.build();
}
Jackson 的樹模型允許用戶以樹形結(jié)構(gòu)操作 JSON 數(shù)據(jù),例如 JsonNode
和 ObjectNode
類,支持更靈活的數(shù)據(jù)訪問與修改。樹模型操作適合需要動態(tài)或未知 JSON 結(jié)構(gòu)的場景。
JsonNode
是 Jackson 樹模型的核心接口,ObjectNode
和 ArrayNode
是其實(shí)現(xiàn)類,用于存儲 JSON 對象和數(shù)組。ObjectMapper mapper = new ObjectMapper();
JsonNode rootNode = mapper.readTree(jsonString); // 讀取 JSON 字符串
String name = rootNode.get("name").asText(); // 訪問字段
在 JsonNode
的實(shí)現(xiàn)中,Jackson 提供了不同的子類來處理 JSON 數(shù)據(jù)節(jié)點(diǎn),比如 TextNode
、BooleanNode
、ArrayNode
等。這種設(shè)計使得 Jackson 能夠輕松地在樹節(jié)點(diǎn)中靈活讀取和寫入 JSON 數(shù)據(jù)。
Jackson 的模塊化設(shè)計允許用戶加載第三方模塊來擴(kuò)展其功能。jackson-module
系列包含了對 JDK8 類型、Java時間類、Kotlin 等支持。這些模塊通過 Module
類來注冊和管理,支持自定義序列化和反序列化器。
registerModule()
方法可以動態(tài)加載擴(kuò)展模塊。ObjectMapper mapper = new ObjectMapper();
mapper.registerModule(new JavaTimeModule()); // 添加對 Java 時間類的支持
通過源碼分析,V 哥發(fā)現(xiàn),Jackson實(shí)在優(yōu)秀,體現(xiàn)了優(yōu)秀的設(shè)計架構(gòu),比如:流式解析提供了高性能支持,數(shù)據(jù)綁定實(shí)現(xiàn)了靈活的對象映射,注解處理讓開發(fā)者可以細(xì)粒度控制序列化過程,同時還支持?jǐn)U展模塊。這種設(shè)計使得 Jackson 適用于多種復(fù)雜的 JSON 處理場景。
再來看 Gson,Gson 的源碼實(shí)現(xiàn)相對簡潔,主要專注于 JSON 與 Java 對象的序列化和反序列化。其實(shí)現(xiàn)涉及的核心類包括 Gson
、TypeAdapter
、JsonElement
、JsonParser
等。下面我們分步驟分析 Gson 的主要源碼實(shí)現(xiàn)過程。
Gson 的核心類是 Gson
,它負(fù)責(zé) JSON 與 Java 對象之間的相互轉(zhuǎn)換。Gson
中的 toJson()
和 fromJson()
方法是核心接口,它們分別用于將 Java 對象轉(zhuǎn)換為 JSON 字符串,以及將 JSON 字符串解析為 Java 對象。Gson 的設(shè)計依賴于反射和注解,TypeAdapter
類用于自定義對象的序列化和反序列化。
在 Gson
中,fromJson()
方法用于 JSON 到 Java 對象的轉(zhuǎn)換。其主要步驟包括解析 JSON、匹配類型、反射創(chuàng)建對象等。
fromJson()
方法是 Gson 解析 JSON 字符串的入口。在調(diào)用時會根據(jù)給定的類型,將 JSON 轉(zhuǎn)換為對應(yīng)的 Java 對象。public <T> T fromJson(String json, Class<T> classOfT) throws JsonSyntaxException {
// 使用 JsonReader 逐字符讀取 JSON 數(shù)據(jù)
JsonReader jsonReader = new JsonReader(new StringReader(json));
return fromJson(jsonReader, classOfT);
}
fromJson(JsonReader reader, Type typeOfT)
方法通過調(diào)用 getAdapter(TypeToken.get(typeOfT))
來獲取 TypeAdapter
,然后調(diào)用 read()
方法讀取 JSON 數(shù)據(jù)并轉(zhuǎn)換為對象。public <T> T fromJson(JsonReader reader, Type typeOfT) throws JsonIOException, JsonSyntaxException {
TypeAdapter<T> adapter = getAdapter(TypeToken.get(typeOfT));
return adapter.read(reader);
}
TypeAdapter
是 Gson 中的核心接口,用于控制對象序列化和反序列化的過程。Gson 提供了多種類型的 TypeAdapter
,并支持用戶自定義 TypeAdapter
。
read(JsonReader in)
方法會遍歷 JSON 數(shù)據(jù)并創(chuàng)建 Java 對象。例如,在 ReflectiveTypeAdapterFactory.Adapter
中會通過反射讀取 JSON 數(shù)據(jù)并賦值給 Java 對象的字段。@Override
public T read(JsonReader in) throws IOException {
T instance = constructor.construct();
in.beginObject();
while (in.hasNext()) {
String name = in.nextName();
// 找到字段對應(yīng)的 TypeAdapter,賦值給 Java 對象
Field field = fields.get(name);
field.set(instance, fieldAdapter.read(in));
}
in.endObject();
return instance;
}
Gson 的 toJson()
方法用于將 Java 對象序列化為 JSON 字符串。實(shí)現(xiàn)思路類似,首先獲取對象的 TypeAdapter
,然后通過 write()
方法將數(shù)據(jù)寫入 JSON。
toJson()
方法內(nèi)部通過 getAdapter()
獲取 TypeAdapter
,然后調(diào)用 write()
生成 JSON。public void toJson(Object src, Appendable writer) throws JsonIOException {
if (src != null) {
toJson(src, src.getClass(), writer);
} else {
writer.append("null");
}
}
write(JsonWriter out, T value)
方法用于將 Java 對象寫入 JSON。例如,在 ReflectiveTypeAdapterFactory.Adapter
中,它會逐字段將 Java 對象序列化為 JSON 字符串。@Override
public void write(JsonWriter out, T value) throws IOException {
out.beginObject();
for (BoundField boundField : boundFields.values()) {
out.name(boundField.name);
boundField.write(out, value);
}
out.endObject();
}
JsonWriter
是 Gson 中流式輸出 JSON 的工具,配合 TypeAdapter
使用,它可以逐步生成 JSON,適合大對象和復(fù)雜結(jié)構(gòu)。
Gson 使用 TypeToken
處理泛型,以解決 Java 的類型擦除問題。TypeToken
是 Gson 用于保存泛型類型信息的工具類。
new TypeToken<List<String>>(){}.getType()
可以獲取 List<String>
的 Type
對象。Type listType = new TypeToken<List<String>>(){}.getType();
List<String> list = gson.fromJson(json, listType);
TypeToken
的源碼實(shí)現(xiàn)利用了匿名內(nèi)部類來獲取泛型信息,TypeToken
的構(gòu)造方法會調(diào)用 getSuperclassTypeParameter()
來捕獲泛型類型。private static Type getSuperclassTypeParameter(Class<?> subclass) {
Type superclass = subclass.getGenericSuperclass();
if (superclass instanceof ParameterizedType) {
return ((ParameterizedType) superclass).getActualTypeArguments()[0];
}
throw new RuntimeException("Missing type parameter.");
}
Gson 支持注解 @SerializedName
來指定 JSON 字段名,它通過反射獲取字段上的注解并設(shè)置到 Field
對象中,以在序列化和反序列化時使用。
ReflectiveTypeAdapterFactory
中,通過反射獲取字段的注解。如果字段帶有 @SerializedName
注解,則將注解指定的名稱作為 JSON 中的字段名。Field field = ...;
SerializedName annotation = field.getAnnotation(SerializedName.class);
String name = (annotation == null) ? field.getName() : annotation.value();
Gson 提供了 JsonElement
類來表示 JSON 節(jié)點(diǎn),它是一個抽象類,具有 JsonObject
、JsonArray
、JsonPrimitive
和 JsonNull
等子類。
JsonParser
類用于解析 JSON 字符串并返回一個 JsonElement
,適用于不確定 JSON 結(jié)構(gòu)的動態(tài)解析場景。JsonElement jsonTree = JsonParser.parseString(jsonString);
if (jsonTree.isJsonObject()) {
JsonObject jsonObject = jsonTree.getAsJsonObject();
// 可以根據(jù)鍵值訪問
String name = jsonObject.get("name").getAsString();
}
Gson 允許用戶通過 TypeAdapter
和 JsonSerializer
/JsonDeserializer
來自定義序列化和反序列化過程,適用于處理特殊格式的數(shù)據(jù)。
JsonSerializer
和 JsonDeserializer
是接口,用于自定義序列化和反序列化過程,用戶可以實(shí)現(xiàn)這兩個接口,并將其傳入 GsonBuilder
中進(jìn)行注冊。GsonBuilder builder = new GsonBuilder();
builder.registerTypeAdapter(Date.class, new JsonSerializer<Date>() {
@Override
public JsonElement serialize(Date src, Type typeOfSrc, JsonSerializationContext context) {
return new JsonPrimitive(src.getTime()); // 序列化為時間戳
}
});
Gson gson = builder.create();
GsonBuilder
是 Gson 的構(gòu)建類,用于配置 Gson 實(shí)例。可以在 GsonBuilder
中添加自定義的 TypeAdapter
、JsonSerializer
和 JsonDeserializer
,并設(shè)置序列化/反序列化的策略。
GsonBuilder builder = new GsonBuilder();
builder.setPrettyPrinting(); // 格式化 JSON 輸出
builder.registerTypeAdapter(CustomClass.class, new CustomTypeAdapter());
Gson gson = builder.create(); // 創(chuàng)建 Gson 實(shí)例
通過以上的源碼分析,咱們可以看到,Gson 的源碼設(shè)計相對簡潔,適合處理簡單的 JSON 數(shù)據(jù)結(jié)構(gòu)。它的核心設(shè)計思想圍繞 TypeAdapter
、TypeToken
和注解反射來實(shí)現(xiàn)靈活的序列化和反序列化。
Jackson和Gson各有優(yōu)缺點(diǎn),這也符合天下技術(shù)唯有最適合沒有最好的道理, V 哥建議,在選擇使用時,需要根據(jù)自己的項(xiàng)目情況來判斷,才是明智的。
從性能的角度來分析,咱們可以得出以下結(jié)論:
Jackson和Gson各有所長,選擇時應(yīng)根據(jù)具體需求權(quán)衡性能、靈活性和開發(fā)便捷性。
更多建議: