一、Gson的复用
一直有一个担心,对于不同的数据类是否可以用同一个gson实例,今天研究了一下,不仅是可以,而且最好是这样使用。看代码Gson.java中的getAdapter方法,一开始就是在typeTokenCache这个缓存中找type相关的TypeAdapter。
1 2 3 4 5 6 7 8 |
public <T> TypeAdapter<T> getAdapter(TypeToken<T> type) { TypeAdapter<?> cached = typeTokenCache.get(type == null ? NULL_KEY_SURROGATE : type); if (cached != null) { return (TypeAdapter<T>) cached; } //...省略其他代码 } |
因此复用一个gson的实例会省去匹配TypeAdapter(当然还有new Gson())的时间。
如下代码实例:
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 |
import java.util.Random; public class GsonTest { class User{ int id; } class Score { int score; } public static void main(String[] args){ String jsonstr= "{\"id\": "; String jsonstr1= "{\"score\": "; long start = System.currentTimeMillis(); StringBuilder stringBuilder = new StringBuilder(""); Random random = new Random(1000); Gson gson = new Gson(); //复用一个实例 for(int i = 0; i < 1000 ; i++){ stringBuilder.setLength(0); stringBuilder.append(jsonstr).append(random.nextInt(10000)).append("}"); System.out.println(stringBuilder.toString()); //Gson gson = new Gson(); //每次创建实例 User u = gson.fromJson(stringBuilder.toString(), User.class); System.out.println("userid: " + u.id); stringBuilder.setLength(0); stringBuilder.append(jsonstr1).append(random.nextInt(10000)).append("}"); System.out.println(stringBuilder.toString()); Score score = gson.fromJson(stringBuilder.toString(), Score.class); System.out.println("score: " + score.score); } System.out.println("Time: " + (System.currentTimeMillis() - start)); } } |
在我机器上测试不复用的话用时220-260毫秒之间(非常不稳定),复用120毫秒。
二、TypeToken是个什么东东?
TypeToken其实是为了给标识一个泛型类中的T,对于普通的类我们通过getClass().getName就可以得到类的标识,但是对于泛型类,只能得到泛型外层的类名,并不能得到泛型外层类+泛型类这样的全名。
如下代码:
1 2 |
List<Integer> intlist = new ArrayList<Integer>(); System.out.println(intlist.getClass().getName()); |
输出结果是:java.util.ArrayList,而不是java.util.ArrayList<java.lang.Integer>
使用TypeToken来获取就是另外一种情况了,看下面的例子:
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 |
import java.lang.reflect.Type; public class GenericTypeTest { static class GType<T> { T t; public GType(T t) { this.t = t; } String getGtName(){ return t.getClass().getName(); } } public static void main(String[] args){ Integer i = new Integer(10); GType<Integer> gTypeInt = new GType<Integer>(i); System.out.println("Type from getClass().getName(): " + gTypeInt.getGtName()); GType<GType<Integer>> gtt = new GType<GType<Integer>>(gTypeInt); System.out.println("Type from getClass().getName(): " + gtt.getGtName()); Type type = new TypeToken<GType<Integer>>(){}.getType(); System.out.println("Type from typetoken: " + type.toString()); } } |
输出结果:
1 2 3 |
Type from getClass().getName(): java.lang.Integer Type from getClass().getName(): cn.bcoder.libgsontest.GenericTypeTest$GType Type from typetoken: cn.bcoder.libgsontest.GenericTypeTest$GType<java.lang.Integer> |
三、TypeAdapter的使用
四、一些类的作用
1. ConstructorConstructor – 返回一个函数可以给要操作的类新建一个实例对象。
2. InstanceCreator – 用于给没有无参数构造函数的类,创建一个实例的一个接口。解释:gson在反序列时需要创建类的一个实例,如果该类没有无参数构造函数(如:三方库中的类),则会出现异常,所以开发者需要新建一个类实现这个接口,并用该类可用的构造函数新建一个实例。并使用下面方式Gson gson = new GsonBuilder().registerTypeAdapter(Id.class, new IdInstanceCreator()).create();注册到gson中。
3. FutureTypeAdapter – 用于缓存TypeAdapter。为什么不用TypeAdapter的实例缓存?因为TypeAdapter是个虚类 :-D