Gson解析泛型对象时TypeToken的使用方法

参考: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());//com.chen.fanxing.Test$DataBean@4b9af9a9

		
	}
	
	 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的这个属性的类型也进行参数化了,即所谓的参数化类型。

小结:

  1. 与普通的 Object 代替一切类型这样简单粗暴而言,泛型使得数据的类别可以像参数一样由外部传递进来。它提供了一种扩展能力。它更符合面向抽象开发的软件编程宗旨。
  2. 当具体的类型确定后,泛型又提供了一种类型检测的机制,只有相匹配的数据才能正常的赋值,否则编译器就不通过。所以说,它是一种类型安全检测机制,一定程度上提高了软件的安全性防止出现低级的失误。(可以通过反射破解)
  3. 泛型提高了程序代码的可读性,不必要等到运行的时候才去强制转换,在定义或者实例化阶段,因为 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 种形式。

  1. <?> 被称作无限定的通配符。
  2. <? extends T> 被称作有上限的通配符。
  3. <? 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);
  }

猜你喜欢

转载自blog.csdn.net/chenpdsu/article/details/81076233