美文网首页
gson中new TypeToken>

gson中new TypeToken>

作者: 勤劳的蚂蚁 | 来源:发表于2020-12-25 13:54 被阅读0次

参考:
JAVA匿名内部类(Anonymous Classes)
gson中对构造方法TypeToken()的探究
Gson中TypeToken如何实现获取参数类型
情景引入:
在使用GSON解析一段JSON数组时,需要借助TypeToken将期望解析成的数据类型传入到fromJson()方法中,如下

   List<BottomNavigationConfigBean> mblist = gson.fromJson (indexInfoList, new TypeToken<List<BottomNavigationConfigBean>> () {
            }.getType ());

疑问:不清楚为什么JSON转换为对象的时候,new TypeToken()后面还要跟着一个大括号?
通常是通过 new 构造方法().方法名() 来调用某个类中的方法
但截图中使用了 new 构造方法(){}.方法名() ,构造方法后面多了一个大括号?

1. new TypeToken<List<Person>>(){}是一个匿名内部类

匿名类表达式包含以下内部分:
操作符:new;
一个要实现的接口或要继承的类,案例一中的匿名类实现了HellowWorld接口,案例二中的匿名内部类继承了Animal父类;
一对括号,如果是匿名子类,与实例化普通类的语法类似,如果有构造参数,要带上构造参数;如果是实现一个接口,只需要一对空括号即可;
一段被"{}"括起来类声明主体;
末尾的";"号(因为匿名类的声明是一个表达式,是语句的一部分,因此要以分号结尾)。

public class AnimalTest {

    private final String ANIMAL = "动物";

    public void accessTest() {
        System.out.println("匿名内部类访问其外部类方法");
    }

    class Animal {
        private String name;

        public Animal(String name) {
            this.name = name;
        }

        public void printAnimalName() {
            System.out.println(bird.name);
        }
    }

    // 鸟类,匿名子类,继承自Animal类,可以覆写父类方法
    Animal bird = new Animal("布谷鸟") {

        @Override
        public void printAnimalName() {
            accessTest();           // 访问外部类成员
            System.out.println(ANIMAL);  // 访问外部类final修饰的变量
            super.printAnimalName();
        }
    };

    public void print() {
        bird.printAnimalName();
    }

    public static void main(String[] args) {

        AnimalTest animalTest = new AnimalTest();
        animalTest.print();
    }
}

2. 问题探索

猜测这里使用了“匿名内部类”,但不明白为什么要这么做,于是做个实验,删除构造方法后面的{}


image.png

报错提示:‘TypeToken()’ has protected access in ‘com.google.gson.reflect.TypeToken’
关键词:protected

前往TypeToken这个类的源码处看一看:


image.png

构造方法TypeToken()被protected修饰,有如下特点:

protected
如果构造函数是protected,那么该类可以继承,可以在被包内其他类中产生实例,但是无法在包外或者子类以外的地方产生实例

划重点:如果构造函数是protected,无法在包外或者子类以外的地方产生实例

因此在使用构造方法TypeToken()进行实例化时,需要先通过匿名内部类继承TypeToken这个类,然后才能进行实例化,进而继续调用getType()方法。

new TypeToken<List<Person>>(){}是一个匿名内部类,其等价MyTypeToken<List<Person>> extends TypeToken(){}.

为什么要用protected来修饰构造方法TypeToken()呢?
为了拿持有泛型。protected修饰的构造方法,对于非同包需要先用一个类来继承父类才能new,然后通过继承的那个类来拿持有泛型。alibaba的fastjson里也有个类似的类,套路相似。

看代码:

 /**
   * Constructs a new type literal. Derives represented class from type
   * parameter.
   *
   * <p>Clients create an empty anonymous subclass. Doing so embeds the type
   * parameter in the anonymous class's type hierarchy so we can reconstitute it
   * at runtime despite erasure.
  构造一个新的类型文本。从类型派生表示的类参数。
*  客户端创建一个空的匿名子类。这样做会嵌入类型匿名类的类型层次结构中的参数,以便我们在运行时删除后可以重新构造它。
   */
  @SuppressWarnings("unchecked")
  protected TypeToken() {
    this.type = getSuperclassTypeParameter(getClass());
    this.rawType = (Class<? super T>) $Gson$Types.getRawType(type);
    this.hashCode = type.hashCode();
  }

 /**
   * Returns the type from super class's type parameter in {@link $Gson$Types#canonicalize
   * canonical form}.
返回从规范化超类的类型参数
   */
  static Type getSuperclassTypeParameter(Class<?> subclass) {

  //获取到子类的父类Type(/感觉是返回类 所有的参数信息 ??)
    Type superclass = subclass.getGenericSuperclass();
    if (superclass instanceof Class) {
      throw new RuntimeException("Missing type parameter.");
    }
////将Type类型向下转型为参数化类型ParameterizedType
    ParameterizedType parameterized = (ParameterizedType) superclass;
////这里getActualTypeArguments()返回的是一个数组,由于只有一个泛型参数,直接[0]。
    return $Gson$Types.canonicalize(parameterized.getActualTypeArguments()[0]);
  }

Type:

其是一个接口java.lang.reflect.Type,主要有5类:
raw types:一般类型,例如:String,Collections ,Math,Number…
parameterized types : 参数化类型,例如:`List<String>`集合中常用…
array types : 数组类型
type variables :类型变量,不确定其类型,例如`List<? extends Person>`
primitive types : 基本类型,int,float…

详细参见:[http://blog.csdn.net/kaka123ac/article/details/4470813](http://blog.csdn.net/kaka123ac/article/details/4470813)

getSuperClass() 与 getGenericSuperclass()区别:

前者,返回表示此 Class 所表示的实体(类、接口、基本类型或 void)的超类的 Class(由于编译擦除,没有显示泛型参数:在运行期间,泛型参数类型一律为Object类型)。
后者,返回表示此 Class 所表示的实体(类、接口、基本类型或 void)的直接超类的 Type(包含泛型参数)。

详细参见: [http://www.cnblogs.com/maokun/p/6773203.html](http://www.cnblogs.com/maokun/p/6773203.html)

相关文章

网友评论

      本文标题:gson中new TypeToken>

      本文链接:https://www.haomeiwen.com/subject/qawbnktx.html