Android Gson基础数据类型转换逻辑深度剖析(6)

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字符串时,基础数据类型的转换流程如下:

  1. Gson根据对象类型查找对应的TypeAdapter
  2. 调用TypeAdapter的write方法
  3. TypeAdapter通过JsonWriter将数据写入JSON流
  4. JsonWriter根据数据类型生成相应的JSON格式

2.2 反序列化流程概述

当Gson将JSON字符串反序列化为Java对象时,基础数据类型的转换流程如下:

  1. Gson根据目标类型查找对应的TypeAdapter
  2. 调用TypeAdapter的read方法
  3. TypeAdapter通过JsonReader从JSON流中读取数据
  4. 将读取的数据转换为目标类型的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提供了对BigIntegerBigDecimal的支持:

// 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的更新和改进
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Android 小码蜂

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值
OSZAR »