欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

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

小结:

  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);
  }