Android Gson基础数据类型转换逻辑深度剖析
一、Gson基础数据类型转换概述
1.1 Gson框架的核心功能
Gson作为Google开发的JSON处理库,在Android平台上广泛应用于JSON数据的序列化和反序列化。其核心功能包括:
- 对象到JSON的序列化:将Java对象转换为JSON字符串
- JSON到对象的反序列化:将JSON字符串转换为Java对象
- 支持复杂数据结构:包括嵌套对象、集合、泛型等
- 自定义序列化策略:允许用户自定义类型的序列化和反序列化方式
1.2 基础数据类型转换的重要性
基础数据类型(如int、long、String、boolean等)是构建复杂数据结构的基石。Gson对基础数据类型的转换逻辑直接影响到整个框架的性能和稳定性。理解其转换原理有助于:
- 优化JSON数据处理效率
- 解决类型转换异常问题
- 自定义特定数据类型的转换规则
- 深入理解Gson框架的工作机制
1.3 基础数据类型转换的核心组件
Gson中处理基础数据类型转换的核心组件包括:
- TypeAdapter:定义类型与JSON之间的转换接口
- TypeAdapterFactory:创建TypeAdapter的工厂类
- JsonReader/JsonWriter:JSON数据的读取和写入工具
- PrimitiveTypeAdapter:处理基础数据类型的适配器
- ReflectiveTypeAdapterFactory:基于反射处理对象类型的适配器
二、基础数据类型转换的核心流程
2.1 序列化流程概述
当Gson将Java对象序列化为JSON字符串时,基础数据类型的转换流程如下:
- Gson根据对象类型查找对应的TypeAdapter
- 调用TypeAdapter的write方法
- TypeAdapter通过JsonWriter将数据写入JSON流
- JsonWriter根据数据类型生成相应的JSON格式
2.2 反序列化流程概述
当Gson将JSON字符串反序列化为Java对象时,基础数据类型的转换流程如下:
- Gson根据目标类型查找对应的TypeAdapter
- 调用TypeAdapter的read方法
- TypeAdapter通过JsonReader从JSON流中读取数据
- 将读取的数据转换为目标类型的Java对象
2.3 类型适配器的注册与查找
Gson在初始化时会注册一系列默认的TypeAdapter,包括处理基础数据类型的适配器。这些适配器存储在一个适配器注册表中,当需要进行类型转换时,Gson会根据目标类型从注册表中查找合适的适配器。
// Gson类中的适配器注册表初始化
private final Map<TypeToken<?>, TypeAdapter<?>> typeTokenCache = new HashMap<>();
// 注册默认的基础数据类型适配器
private void registerTypeAdapters(Map<TypeToken<?>, TypeAdapter<?>> typeTokenCache) {
// 注册字符串适配器
typeTokenCache.put(TypeToken.get(String.class), STRING);
// 注册布尔值适配器
typeTokenCache.put(TypeToken.get(boolean.class), BOOLEAN);
typeTokenCache.put(TypeToken.get(Boolean.class), BOOLEAN);
// 注册字符适配器
typeTokenCache.put(TypeToken.get(char.class), CHARACTER);
typeTokenCache.put(TypeToken.get(Character.class), CHARACTER);
// 注册数值类型适配器
typeTokenCache.put(TypeToken.get(byte.class), BYTE);
typeTokenCache.put(TypeToken.get(Byte.class), BYTE);
typeTokenCache.put(TypeToken.get(short.class), SHORT);
typeTokenCache.put(TypeToken.get(Short.class), SHORT);
typeTokenCache.put(TypeToken.get(int.class), INTEGER);
typeTokenCache.put(TypeToken.get(Integer.class), INTEGER);
typeTokenCache.put(TypeToken.get(long.class), LONG);
typeTokenCache.put(TypeToken.get(Long.class), LONG);
typeTokenCache.put(TypeToken.get(float.class), FLOAT);
typeTokenCache.put(TypeToken.get(Float.class), FLOAT);
typeTokenCache.put(TypeToken.get(double.class), DOUBLE);
typeTokenCache.put(TypeToken.get(Double.class), DOUBLE);
}
三、数值类型的转换原理
3.1 整数类型转换
Gson对整数类型(byte、short、int、long)的转换主要通过TypeAdapters
类中的静态内部类实现。以Integer
类型为例:
// Integer类型的TypeAdapter实现
public static final TypeAdapter<Number> INTEGER = new TypeAdapter<Number>() {
@Override
public Number read(JsonReader in) throws IOException {
if (in.peek() == JsonToken.NULL) {
in.nextNull();
return null;
}
try {
// 从JSON流中读取整数
return in.nextInt();
} catch (NumberFormatException e) {
// 处理非整数格式的异常
throw new JsonSyntaxException(e);
}
}
@Override
public void write(JsonWriter out, Number value) throws IOException {
if (value == null) {
out.nullValue();
return;
}
// 将整数写入JSON流
out.value(value);
}
}.nullSafe();
在反序列化时,JsonReader
会根据当前标记类型调用相应的方法读取整数值:
// JsonReader类中的nextInt方法
public int nextInt() throws IOException {
int result = doPeekInt();
// 移动到下一个标记
pathIndex++;
return result;
}
private int doPeekInt() throws IOException {
JsonToken peeked = peek();
if (peeked == JsonToken.NUMBER) {
// 直接解析数字
String value = readNumber();
try {
return Integer.parseInt(value);
} catch (NumberFormatException e) {
throw new MalformedJsonException("Expected an int but was " + value, e);
}
} else if (peeked == JsonToken.STRING) {
// 从字符串解析整数
String value = nextString();
try {
return Integer.parseInt(value);
} catch (NumberFormatException e) {
throw new MalformedJsonException("Expected an int but was " + value, e);
}
} else {
// 处理其他类型的异常
throw new MalformedJsonException("Expected an int but was " + peeked);
}
}
3.2 浮点类型转换
Gson对浮点类型(float、double)的转换逻辑与整数类型类似,但处理方式略有不同。以Double
类型为例:
// Double类型的TypeAdapter实现
public static final TypeAdapter<Number> DOUBLE = new TypeAdapter<Number>() {
@Override
public Number read(JsonReader in) throws IOException {
if (in.peek() == JsonToken.NULL) {
in.nextNull();
return null;
}
try {
// 从JSON流中读取双精度浮点数
return in.nextDouble();
} catch (NumberFormatException e) {
throw new JsonSyntaxException(e);
}
}
@Override
public void write(JsonWriter out, Number value) throws IOException {
if (value == null) {
out.nullValue();
return;
}
// 将双精度浮点数写入JSON流
out.value(value);
}
}.nullSafe();
JsonReader
在读取浮点数时会处理各种可能的数值格式:
// JsonReader类中的nextDouble方法
public double nextDouble() throws IOException {
double result = doPeekDouble();
// 移动到下一个标记
pathIndex++;
return result;
}
private double doPeekDouble() throws IOException {
JsonToken peeked = peek();
if (peeked == JsonToken.NUMBER) {
// 直接解析数字
String value = readNumber();
try {
return Double.parseDouble(value);
} catch (NumberFormatException e) {
throw new MalformedJsonException("Expected a double but was " + value, e);
}
} else if (peeked == JsonToken.STRING) {
// 从字符串解析双精度浮点数
String value = nextString();
try {
return Double.parseDouble(value);
} catch (NumberFormatException e) {
throw new MalformedJsonException("Expected a double but was " + value, e);
}
} else {
// 处理其他类型的异常
throw new MalformedJsonException("Expected a double but was " + peeked);
}
}
3.3 大数类型转换
对于需要高精度处理的场景,Gson提供了对BigInteger
和BigDecimal
的支持:
// BigDecimal类型的TypeAdapter实现
public static final TypeAdapter<BigDecimal> BIG_DECIMAL = new TypeAdapter<BigDecimal>() {
@Override
public BigDecimal read(JsonReader in) throws IOException {
if (in.peek() == JsonToken.NULL) {
in.nextNull();
return null;
}
try {
// 从JSON流中读取BigDecimal
return new BigDecimal(in.nextString());
} catch (NumberFormatException e) {
throw new JsonSyntaxException(e);
}
}
@Override
public void write(JsonWriter out, BigDecimal value) throws IOException {
if (value == null) {
out.nullValue();
return;
}
// 将BigDecimal写入JSON流
out.value(value);
}
}.nullSafe();
四、字符串类型的转换原理
4.1 字符串序列化
Gson在将Java字符串序列化为JSON字符串时,会处理特殊字符的转义:
// String类型的TypeAdapter实现
public static final TypeAdapter<String> STRING = new TypeAdapter<String>() {
@Override
public String read(JsonReader in) throws IOException {
if (in.peek() == JsonToken.NULL) {
in.nextNull();
return null;
}
// 从JSON流中读取字符串
return in.nextString();
}
@Override
public void write(JsonWriter out, String value) throws IOException {
if (value == null) {
out.nullValue();
return;
}
// 将字符串写入JSON流
out.value(value);
}
}.nullSafe();
JsonWriter
在写入字符串时会进行转义处理:
// JsonWriter类中的value方法
public JsonWriter value(String value) throws IOException {
if (value == null) {
return nullValue();
}
// 写入字符串值,自动处理转义
beforeValue(true);
string(value);
return this;
}
private void string(String value) throws IOException {
out.write('"');
// 处理字符串中的特殊字符
for (int i = 0, length = value.length(); i < length; i++) {
char c = value.charAt(i);
switch (c) {
case '"':
out.write("\\\"");
break;
case '\\':
out.write("\\\\");
break;
case '\b':
out.write("\\b");
break;
case '\f':
out.write("\\f");
break;
case '\n':
out.write("\\n");
break;
case '\r':
out.write("\\r");
break;
case '\t':
out.write("\\t");
break;
default:
if (c <= 0x1F) {
// 控制字符转义为\uXXXX格式
out.write(String.format("\\u%04x", (int) c));
} else {
out.write(c);
}
break;
}
}
out.write('"');
}
4.2 字符串反序列化
Gson在将JSON字符串反序列化为Java字符串时,会处理转义字符的还原:
// JsonReader类中的nextString方法
public String nextString() throws IOException {
JsonToken peeked = peek();
if (peeked == JsonToken.STRING) {
// 直接读取字符串
return readString();
} else if (peeked == JsonToken.NUMBER) {
// 数字转换为字符串
return readNumber();
} else if (peeked == JsonToken.BOOLEAN) {
// 布尔值转换为字符串
return Boolean.toString(readBoolean());
} else if (peeked == JsonToken.NULL) {
// 空值处理
nextNull();
return null;
} else {
throw new MalformedJsonException("Expected a string but was " + peeked);
}
}
private String readString() throws IOException {
// 读取双引号之间的内容
int peeked = in.read();
if (peeked != '"') {
throw new MalformedJsonException("Expected \"");
}
return readString$18652328();
}
private String readString$18652328() throws IOException {
StringBuilder builder = null;
int start = pos;
int limit = buf.length;
while (true) {
// 查找下一个转义字符或双引号
for (int i = pos; i < limit; i++) {
char c = buf[i];
if (c == '"') {
if (builder == null) {
// 没有转义字符,直接返回
String result = new String(buf, start, i - start);
pos = i + 1;
return result;
} else {
builder.append(buf, start, i - start);
pos = i + 1;
return builder.toString();
}
} else if (c == '\\') {
if (builder == null) {
builder = new StringBuilder();
}
builder.append(buf, start, i - start);
pos = i + 1;
// 处理转义字符
builder.append(readEscapeCharacter());
start = pos;
limit = buf.length;
break;
}
}
// 如果缓冲区已读完,继续读取
if (pos == limit) {
int count = in.read(buf, 0, buf.length);
if (count == -1) {
throw new MalformedJsonException("Unterminated string");
}
start = 0;
pos = 0;
limit = count;
}
}
}
private char readEscapeCharacter() throws IOException {
int c = in.read();
if (c == -1) {
throw new MalformedJsonException("Unterminated escape sequence");
}
switch (c) {
case '"':
case '\\':
case '/':
return (char) c;
case 'b':
return '\b';
case 'f':
return '\f';
case 'n':
return '\n';
case 'r':
return '\r';
case 't':
return '\t';
case 'u':
// 处理Unicode转义序列
int codePoint = 0;
for (int i = 0; i < 4; i++) {
int d = in.read();
if (d == -1) {
throw new MalformedJsonException("Unterminated escape sequence");
}
int digit = Character.digit((char) d, 16);
if (digit == -1) {
throw new MalformedJsonException("Invalid escape sequence");
}
codePoint = (codePoint << 4) + digit;
}
return (char) codePoint;
default:
throw new MalformedJsonException("Invalid escape sequence");
}
}
五、布尔类型的转换原理
5.1 布尔类型序列化
Gson在将Java布尔值序列化为JSON时,会生成"true"或"false"字符串:
// Boolean类型的TypeAdapter实现
public static final TypeAdapter<Boolean> BOOLEAN = new TypeAdapter<Boolean>() {
@Override
public Boolean read(JsonReader in) throws IOException {
JsonToken peeked = in.peek();
if (peeked == JsonToken.BOOLEAN) {
// 读取布尔值
return in.nextBoolean();
} else if (peeked == JsonToken.NULL) {
// 处理空值
in.nextNull();
return null;
} else if (peeked == JsonToken.STRING) {
// 从字符串解析布尔值
String value = in.nextString();
if (value == null) {
return null;
}
value = value.trim();
if (value.isEmpty()) {
return null;
}
if ("true".equalsIgnoreCase(value)) {
return true;
} else if ("false".equalsIgnoreCase(value)) {
return false;
}
throw new JsonSyntaxException("Invalid boolean value: " + value);
} else {
throw new JsonSyntaxException("Expected BOOLEAN or NULL but was " + peeked);
}
}
@Override
public void write(JsonWriter out, Boolean value) throws IOException {
if (value == null) {
out.nullValue();
} else {
// 写入布尔值
out.value(value);
}
}
}.nullSafe();
JsonWriter
在写入布尔值时会直接输出"true"或"false":
// JsonWriter类中的value方法(处理布尔值)
public JsonWriter value(boolean value) throws IOException {
beforeValue(true);
out.write(value ? "true" : "false");
return this;
}
5.2 布尔类型反序列化
Gson在将JSON布尔值反序列化为Java布尔值时,会处理"true"和"false"字符串:
// JsonReader类中的nextBoolean方法
public boolean nextBoolean() throws IOException {
boolean result = doPeekBoolean();
// 移动到下一个标记
pathIndex++;
return result;
}
private boolean doPeekBoolean() throws IOException {
JsonToken peeked = peek();
if (peeked == JsonToken.BOOLEAN) {
// 读取布尔值标记
String value = readBoolean$18652328();
return "true".equals(value);
} else if (peeked == JsonToken.STRING) {
// 从字符串解析布尔值
String value = nextString();
if ("true".equalsIgnoreCase(value)) {
return true;
} else if ("false".equalsIgnoreCase(value)) {
return false;
}
throw new MalformedJsonException("Expected a boolean but was " + value);
} else {
throw new MalformedJsonException("Expected a boolean but was " + peeked);
}
}
六、字符类型的转换原理
6.1 字符类型序列化
Gson在将Java字符序列化为JSON时,会将字符转换为字符串:
// Character类型的TypeAdapter实现
public static final TypeAdapter<Character> CHARACTER = new TypeAdapter<Character>() {
@Override
public Character read(JsonReader in) throws IOException {
if (in.peek() == JsonToken.NULL) {
in.nextNull();
return null;
}
// 从JSON流中读取字符
String s = in.nextString();
if (s.length() != 1) {
throw new JsonSyntaxException("Expecting character, got: " + s);
}
return s.charAt(0);
}
@Override
public void write(JsonWriter out, Character value) throws IOException {
if (value == null) {
out.nullValue();
return;
}
// 将字符写入JSON流
out.value(String.valueOf(value));
}
}.nullSafe();
6.2 字符类型反序列化
Gson在将JSON字符串反序列化为Java字符时,会检查字符串长度是否为1:
// JsonReader类中处理字符反序列化的相关代码
public String nextString() throws IOException {
JsonToken peeked = peek();
if (peeked == JsonToken.STRING) {
// 读取字符串
return readString();
}
// 其他类型处理...
}
// 在Character的TypeAdapter中调用
String s = in.nextString();
if (s.length() != 1) {
throw new JsonSyntaxException("Expecting character, got: " + s);
}
return s.charAt(0);
七、空值处理机制
7.1 空值序列化
Gson在序列化时处理空值的方式取决于配置:
// GsonBuilder类中的serializeNulls方法
public GsonBuilder serializeNulls() {
this.serializeNulls = true;
return this;
}
// JsonWriter类中的nullValue方法
public JsonWriter nullValue() throws IOException {
if (!lenient && stack.peek() == DANGLING_NAME) {
throw new IllegalStateException("Nesting problem.");
}
beforeValue(false);
out.write("null");
return this;
}
7.2 空值反序列化
Gson在反序列化时会根据目标类型决定如何处理空值:
// 基础类型的TypeAdapter处理空值
public Number read(JsonReader in) throws IOException {
if (in.peek() == JsonToken.NULL) {
in.nextNull();
return null;
}
// 处理非空值...
}
// 对于原始类型,会抛出异常
public int read(JsonReader in) throws IOException {
if (in.peek() == JsonToken.NULL) {
throw new JsonSyntaxException("Cannot parse null into int");
}
// 处理非空值...
}
八、自定义基础数据类型转换
8.1 自定义TypeAdapter
开发者可以通过实现TypeAdapter
接口来自定义基础数据类型的转换逻辑:
// 自定义Integer类型的TypeAdapter
public class CustomIntegerTypeAdapter extends TypeAdapter<Integer> {
@Override
public Integer read(JsonReader in) throws IOException {
if (in.peek() == JsonToken.NULL) {
in.nextNull();
return null;
}
// 自定义读取逻辑,例如将字符串"NA"转换为null
String value = in.nextString();
if ("NA".equalsIgnoreCase(value)) {
return null;
}
return Integer.parseInt(value);
}
@Override
public void write(JsonWriter out, Integer value) throws IOException {
if (value == null) {
out.value("NA"); // 自定义空值表示
return;
}
out.value(value);
}
}
8.2 注册自定义TypeAdapter
将自定义的TypeAdapter注册到Gson中:
// 注册自定义TypeAdapter
Gson gson = new GsonBuilder()
.registerTypeAdapter(Integer.class, new CustomIntegerTypeAdapter())
.registerTypeAdapter(int.class, new CustomIntegerTypeAdapter())
.create();
8.3 使用TypeAdapterFactory
更灵活的方式是使用TypeAdapterFactory
:
// 自定义TypeAdapterFactory
public class CustomTypeAdapterFactory implements TypeAdapterFactory {
@Override
public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> type) {
if (type.getRawType() == Integer.class || type.getRawType() == int.class) {
// 为Integer和int类型提供自定义适配器
@SuppressWarnings("unchecked")
TypeAdapter<T> result = (TypeAdapter<T>) new CustomIntegerTypeAdapter();
return result;
}
return null; // 其他类型使用默认适配器
}
}
// 注册TypeAdapterFactory
Gson gson = new GsonBuilder()
.registerTypeAdapterFactory(new CustomTypeAdapterFactory())
.create();
九、性能优化与最佳实践
9.1 缓存TypeAdapter实例
为避免重复创建TypeAdapter实例,可以缓存常用的适配器:
// 缓存TypeAdapter实例
private static final TypeAdapter<Integer> INTEGER_ADAPTER = new Gson().getAdapter(Integer.class);
// 在需要使用的地方直接使用缓存的适配器
Integer value = INTEGER_ADAPTER.fromJson(json);
9.2 避免不必要的装箱拆箱
对于基础数据类型,尽量使用原始类型而非包装类型,减少装箱拆箱开销:
// 推荐使用原始类型
TypeAdapter<int> intAdapter = gson.getAdapter(int.class);
// 避免使用包装类型
TypeAdapter<Integer> integerAdapter = gson.getAdapter(Integer.class);
9.3 使用优化的JsonReader/JsonWriter
在性能敏感的场景下,可以使用优化的JsonReader/JsonWriter实现:
// 使用BufferedReader包装InputStreamReader提高读取性能
InputStreamReader reader = new InputStreamReader(inputStream, StandardCharsets.UTF_8);
BufferedReader bufferedReader = new BufferedReader(reader);
JsonReader jsonReader = new JsonReader(bufferedReader);
十、总结与展望
10.1 基础数据类型转换的核心要点
Gson对基础数据类型的转换是整个框架的基石,其核心要点包括:
- 通过TypeAdapter实现类型与JSON之间的转换
- 处理各种特殊情况(如空值、转义字符)
- 提供灵活的自定义机制
- 兼顾性能和易用性
10.2 未来发展方向
随着Java和Android技术的不断发展,Gson基础数据类型转换可能会在以下方面进行改进:
- 进一步优化性能,减少反射开销
- 增强对新数据类型的支持
- 提供更简洁的自定义API
- 更好地集成Java 8+的新特性(如Stream、Optional等)
- 加强与其他Android组件的集成
10.3 对开发者的建议
在使用Gson处理基础数据类型时,开发者可以:
- 深入理解基础数据类型的转换原理
- 合理使用自定义TypeAdapter解决特殊需求
- 注意空值处理和异常处理
- 遵循性能优化最佳实践
- 及时关注Gson的更新和改进