Gson解析泛型对象时TypeToken的使用方法
程序员文章站
2024-03-16 08:38:34
...
参考:https://www.jianshu.com/p/cdea9a8db18b
package com.chen.fanxing;
public class Foo<T> {
T value;
@Override
public String toString() {
return "Foo [value=" + value + "]";
}
}
package com.chen.fanxing;
import java.util.ArrayList;
import java.util.List;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
public class Test {
public static void main(String[] args) {
List<String> l1 =new ArrayList<>();
List<Integer> l2 =new ArrayList<>();
System.out.println(l1.getClass());
System.out.println(l1.getClass() == l2.getClass());// class java.util.ArrayList true
String jsonData = "{\n" +
" \"name\": \"BeJson\"}";
Gson gson = new Gson();
DataBean bean = gson.fromJson(jsonData, DataBean.class);
System.out.println("bean name: " + bean.name);//bean name: BeJson
System.out.println( "bean jsonStr: " + gson.toJson(bean));//bean jsonStr: {"name":"BeJson"}
Foo<DataBean> foo = new Foo<DataBean>();
foo.value = bean;
//测试中使用gson 2.2.4版本,序列化正常
System.out.println("foo jsonstr: "+gson.toJson(foo));//foo jsonstr: {"value":{"name":"BeJson"}}
String teststr ="{\"value\":{\"name\":\"BeJson\"}}";
Foo<DataBean> genericBean = gson.fromJson(teststr, Foo.class);
System.out.println(genericBean.value.toString());
//报错
//Exception in thread "main" java.lang.ClassCastException: com.google.gson.internal.LinkedTreeMap cannot be cast to com.chen.fanxing.Test$DataBean
// at com.chen.fanxing.Test.main(Test.java:31)
TypeToken<Foo<DataBean>> te = new TypeToken<Foo<DataBean>>() {};
System.out.println(te.getType());
//com.chen.fanxing.Foo<com.chen.fanxing.Test$DataBean>
Foo<DataBean> genericBean2 = gson.fromJson(teststr, te.getType());
System.out.println(genericBean2.value.toString());//[email protected]
}
class DataBean{
public String name;
}
}
报错的原因:类型擦除
泛型:参数化类型
public class Cache<T> {
T value;
public Object getValue() {
return value;
}
public void setValue(T value) {
this.value = value;
}
}
即:将value的这个属性的类型也进行参数化了,即所谓的参数化类型。
小结:
- 与普通的 Object 代替一切类型这样简单粗暴而言,泛型使得数据的类别可以像参数一样由外部传递进来。它提供了一种扩展能力。它更符合面向抽象开发的软件编程宗旨。
- 当具体的类型确定后,泛型又提供了一种类型检测的机制,只有相匹配的数据才能正常的赋值,否则编译器就不通过。所以说,它是一种类型安全检测机制,一定程度上提高了软件的安全性防止出现低级的失误。(可以通过反射**)
- 泛型提高了程序代码的可读性,不必要等到运行的时候才去强制转换,在定义或者实例化阶段,因为
Cache<String>
这个类型显化的效果,程序员能够一目了然猜测出代码要操作的数据类型
泛型的定义和使用:
泛型类:
public class Test<T> {
T field1;
}
泛型方法:
package com.chen.fanxing;
public class Test1<T> {
/**
*
* 类型参数也就是尖括号那一部分是写在返回值前面的。
* <T> 中的 T 被称为类型参数,或者说是声明,而方法中的 T 被称为参数化类型,它不是运行时真正的参数
*
*/
//普通方法
public void testMethod(T t) {
System.out.println(t.getClass().getName());//java.lang.String
}
//泛型方法 声明的类型<K>参数作为返回值
//泛型类中的类型参数与泛型方法中的类型参数是没有相应的联系的,泛型方法始终以自己定义的类型参数为准
public <E> E testMethod1(E e) {
return e;
}
//泛型方法 无返回值
public <E> void testMethod2(E e) {
System.out.println(e.getClass().getName());//java.lang.Integer
}
}
泛型接口:
public interface Iterable<T> { }
通配符有 3 种形式。
-
<?>
被称作无限定的通配符。 -
<? extends T>
被称作有上限的通配符。 -
<? super T>
被称作有下限的通配符。
泛型擦除:
泛型是 Java 1.5 版本才引进的概念,在这之前是没有泛型的概念的,但显然,泛型代码能够很好地和之前版本的代码很好地兼容。
这是因为,泛型信息只存在于代码编译阶段,在进入 JVM 之前,与泛型相关的信息会被擦除掉,专业术语叫做类型擦除。
所以Android:Gson通过借助TypeToken获取泛型参数的类型的方法。
Type type = new TypeToken<NetResultBeanNew<SplashPageOutputListBean>>() {
}.getType();
NetResultBeanNew<SplashPageOutputListBean> netResultBean = new Gson().fromJson(data, type);
public class NetResultBeanNew<T>{
T data;
Integer code;
String message;
public T getData() {
return data;
}
public void setData(T data) {
this.data = data;
}
public Integer getCode() {
return code;
}
public void setCode(Integer code) {
this.code = code;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
}
Retrofit中GsonConverterFactory.create()原理也是如此。
Retrofit.Builder builder = new Retrofit.Builder()
.baseUrl(baseUrl)
.client(getClient(baseUrl, provider))
.addConverterFactory(GsonConverterFactory.create());
@Override
public Converter<ResponseBody, ?> responseBodyConverter(Type type, Annotation[] annotations,
Retrofit retrofit) {
TypeAdapter<?> adapter = gson.getAdapter(TypeToken.get(type));
return new GsonResponseBodyConverter<>(gson, adapter);
}
@Override
public Converter<?, RequestBody> requestBodyConverter(Type type,
Annotation[] parameterAnnotations, Annotation[] methodAnnotations, Retrofit retrofit) {
TypeAdapter<?> adapter = gson.getAdapter(TypeToken.get(type));
return new GsonRequestBodyConverter<>(gson, adapter);
}
上一篇: Java 上一个公用的Gson解析方法