您的位置:首页 > 移动开发 > Android开发

Gson中TypeToken如何实现获取参数类型

2017-07-18 23:09 489 查看
情景引入:

在使用GSON解析一段JSON数组时,需要借助TypeToken将期望解析成的数据类型传入到fromJson()方法中,如下:

List<Person> people = gson.fromJson(jsonData, new TypeToken<List<Person>>(){}.getType());


————出自《第一行代码》


假设一段JSON格式的数据如下:

[{"name":"Tom","age":"10"},
{"name":"Lucy","age":"11"},
{"name":"Lily","age":"11"}]


那木,
new TypeToken<List<Person>>(){}.getType()
是怎么获取到泛型参数类型的呢?

解析:

首先,
new TypeToken<List<Person>>(){}
是一个匿名内部类,其等价
MyTypeToken<List<Person>> extends TypeToken(){}
,但是{}里是空的,既然什么都没有改变,为什么还要这么用呢?下面看源码

进一步,TypeToken源码如下:

public class TypeToken<T> {
final Class<? super T> rawType;
final Type type;
final int hashCode;

//这里的空参构造方法权限修饰符是protected,那木只有其子类可访问,预示着要使用子类构造。
protected TypeToken() {
this.type = getSuperclassTypeParameter(this.getClass());//这里传入的子类,后面2行不用看
this.rawType = Types.getRawType(this.type);
this.hashCode = this.type.hashCode();
}

...

static Type getSuperclassTypeParameter(Class<?> subclass) {
Type superclass = subclass.getGenericSuperclass();//获取到子类的父类Type
if(superclass instanceof Class) {
throw new RuntimeException("Missing type parameter.");
} else {
ParameterizedType parameterized = (ParameterizedType)superclass;//将Type类型向下转型为参数化类型ParameterizedType
return Types.canonicalize(parameterized.getActualTypeArguments()[0]);//这里getActualTypeArguments()返回的是一个数组,由于只有一个泛型参数,直接[0]。
}
}


若是还不是太明白,那就是Java这块的东西还不熟。上面的原码部分牵涉到Java的知识点:

Type:

其是一个接口java.lang.reflect.Type,主要有5类:

raw types:一般类型,例如:String,Collections ,Math,Number…

parameterized types : 参数化类型,例如:
List<String>
集合中常用…

array types : 数组类型

type variables :类型变量,不确定其类型,例如
List<? extends Person>


primitive types : 基本类型,int,float…

详细参见:http://blog.csdn.net/kaka123ac/article/details/4470813

getSuperClass() 与 getGenericSuperclass()区别:

前者,返回表示此 Class 所表示的实体(类、接口、基本类型或 void)的超类的 Class(由于编译擦除,没有显示泛型参数:在运行期间,泛型参数类型一律为Object类型)。

后者,返回表示此 Class 所表示的实体(类、接口、基本类型或 void)的直接超类的 Type(包含泛型参数)。

详细参见: http://www.cnblogs.com/maokun/p/6773203.html

GSON源码中Types.canonicalize方法,将Java 中的Type实现,转化为自己内部的数据实现,想要继续探讨,可以去看源码或者参见:https://my.oschina.net/u/874727/blog/750473

最后,我们来实践一下,实现Java中如何获取参数类型,TypeToken内部就是Java实现,然后转换。直接上代码:

public class TypeToken1<String> {

public TypeToken1() {
}
//为了测试,这个类什么都不干,手动去获取参数类型String
}

----------

public class TypeTokenTest {
public static void main(String[] args){

Type mySuperClass = new TypeToken1<String>(){}.getClass().getGenericSuperclass();
Type type = ((ParameterizedType) mySuperClass).getActualTypeArguments()[0];
System.out.println("获得的泛型参数:"+type);

}
}


运行结果:

获得的泛型参数:class java.lang.String

Process finished with exit code 0
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  gson TypeToken Android