您的位置:首页 > 编程语言 > Java开发

Java进阶(四)Java反射TypeToken解决泛型运行时类型擦除问题

2018-03-18 09:51 483 查看
 

Java进阶(四)Java反射TypeToken解决泛型运行时类型擦除问题

标签: gson class java 泛型 json2015年05月06日 16:50:5357247人阅读 评论(1) 收藏 举报

 分类:Java(68) 

版权声明:本文为博主原创文章,未经博主允许不得转载。 http://blog.csdn.net/sunhuaqiang1/article/details/45537809在开发时,遇到了下面这条语句,不懂,然习之。  
private List<MyZhuiHaoDetailModel> listLottery = new ArrayList<MyZhuiHaoDetailModel>();
 
Gson gson=new Gson();
JSONObject object=new JSONObject(callbackValue);
 
listLottery =  gson.fromJson(object.getString("lists"),
new TypeToken<List<MyZhuiHaoDetailModel>>() {
}.getType());
 
GSON提供了 TypeToken 这个类来帮助我们捕获(capture)像List<MyZhuiHaoDetailModel>这样的泛型信息。上文创建了一个匿名内部类,这样,Java编译器就会把泛型信息编译到这个匿名内部类里,然后在运行时就可以被 getType()方法用反射API提取到。
 
下面来看看gson的反序列化,Gson提供了fromJson()方法来实现从Json相关对象到java实体的方法。
 
在日常应用中,我们一般都会碰到两种情况,转成单一实体对象和转换成对象列表或者其他结构。
 
先来看第一种:
 
比如json字符串为:{"name":"name0","age":0}
 
代码:
 
Person person = gson.fromJson(str, Person.class);
提供两个参数,分别是json字符串以及需要转换对象的类型。
 
第二种,转换成列表类型:
 
代码:
 
List<Person> ps = gson.fromJson(str, new TypeToken<List<Person>>(){}.getType());
for(int i = 0; i < ps.size() ; i++)
{
     Person p = ps.get(i);
     System.out.println(p.toString());
}
可以看到上面的代码使用了TypeToken,它是gson提供的数据类型转换器,可以支持各种数据集合类型转换。
 
经过比较,gson和其他现有java json类库最大的不同是gson需要序列化的实体类不需要使用annotation来标识需要序列化得字段,同时gson又可以通过使用annotation来灵活配置需要序列化的字段。
 
另外,java反射包中的TypeToken类是用来解决java运行时泛型类型被擦除的问题的,有点不好理解,我们通过一个例子来认识什么是泛型的运行时类型擦除。        ArrayList<String> stringList = Lists.newArrayList();         ArrayList<Integer> intList = Lists.newArrayList();               System.out.println("intList type is " + intList.getClass());          System.out.println("stringList type is " + stringList.getClass());        System.out.println(stringList.getClass().isAssignableFrom(intList.getClass()));
上面的代码我们声明了两个泛型的ArrayList类型,一个泛型的类型参数是String,另外一个是Integer;然后我们输出了两个泛型的Class,并输出两个list的类型是否是同一个list。我们看下输出的结果:intList type is class java.util.ArrayListstringList type is class java.util.ArrayListtrue
前两个输出都是java.util.ArrayList,而第三个输出竟然是true,也就是认为stringList和intList的类型是一样的。这就是所谓的泛型类型擦除。运行时我们不知道泛型类型的类型参数是什么了。
TypeToken可以解决这个问题,请看下面代码:        TypeToken<ArrayList<String>> typeToken = new TypeToken<ArrayList<String>>() {};        TypeToken<?> genericTypeToken = typeToken.resolveType(ArrayList.class.getTypeParameters()[0]);        System.out.println(genericTypeToken.getType());
注意上面第一行代码使用了一个空的匿名类。第二行使用了resolveType方法解析出泛型类型,第三行代码打印出泛型类型,输出是:class java.lang.String
可以看出TypeToken解析出了泛型参数的具体类型。
TypeToken的方法列表如下:
方法
描述
getType()
获得包装的java.lang.reflect.Type.
getRawType()
返回大家熟知的运行时类
getSubtype(Class<?>)
返回那些有特定原始类的子类型。举个例子,如果这有一个Iterable并且参数是List.class,那么返回将是List。
getSupertype(Class<?>)
产生这个类型的超类,这个超类是指定的原始类型。举个例子,如果这是一个Set并且参数是Iterable.class,结果将会是Iterable。
isAssignableFrom(type)
如果这个类型是 assignable from 指定的类型,并且考虑泛型参数,返回true。List<? extends Number>是assignable from List,但List没有.
getTypes()
返回一个Set,包含了这个所有接口,子类和类是这个类型的类。返回的Set同样提供了classes()和interfaces()方法允许你只浏览超类和接口类。
isArray()
检查某个类型是不是数组,甚至是<? extends A[]>。
getComponentType()
返回组件类型数组。
 
 
Gson的基本使用就是这么多,至于annotation方面可以参考gson的官方文档,希望能对初学java和gson的同学有所帮助。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐