Json转Map的后出现ClassCastException
运行错误
测试代码
1 | import com.google.gson.Gson |
运行的时候,会抛类型转换错误
1 | class java.util.HashMap |
源码分析
追踪调用栈,发现Gson里面处理number的逻辑,走到 MapTypeAdapterFactory 里面
1 | read:161, MapTypeAdapterFactory$Adapter (com.google.gson.internal.bind) |
- com.google.gson.internal.bind.ObjectTypeAdapter#read上面👆🏻源码可以看到,这里只针对处理了STRING,NUMBER,BOOLEAN,NULL的4中类型,其中对NUMBER类型,都是用Double去接受的。为什么编译的时候OK?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38public Object read(JsonReader in) throws IOException {
JsonToken token = in.peek();
switch (token) {
case BEGIN_ARRAY:
List<Object> list = new ArrayList<Object>();
in.beginArray();
while (in.hasNext()) {
list.add(read(in));
}
in.endArray();
return list;
case BEGIN_OBJECT:
Map<String, Object> map = new LinkedTreeMap<String, Object>();
in.beginObject();
while (in.hasNext()) {
map.put(in.nextName(), read(in));
}
in.endObject();
return map;
case STRING:
return in.nextString();
case NUMBER:
return in.nextDouble();
case BOOLEAN:
return in.nextBoolean();
case NULL:
in.nextNull();
return null;
default:
throw new IllegalStateException();
}
}
类型擦除
所有的泛型都是编译期间概念,在编译之后,运行的时候,是感知不到泛型的。泛型在编译的时候被擦除了,也就是输出class name的时候,还是map本身。泛型会在编译的时候,做检查。例如我们用double去接受,编译器会抛错,尽管运行的时候是double类型。
编译之后再反编译回来, 运行时的逻辑就是这样的,并没有泛型信息。可以看到这里有个强转,而Integer是包装类型,不是基本类型,无法强转,导致抛错。
1 | public static final void main() { |
JS number类型
JSON(JavaScript Object Notation, JS对象简谱),和其他语言有多种数值类型不同,int/longint/float/double等,JS 不分整数和浮点型,所有数字都使用浮点型来储存。
总结
可以成功运行
1 | fun main() { |
1 | class java.util.HashMap |
我的理解是Gson和Json 表示对齐,默认number类型也是用double去解析的,当一个string json转换成map的时候,是感知不到泛型的,实际上的map是map<string,object>类型,而写代码的时候存在泛型过了编译,导致运行的时候抛错