Principio Java-TypeToken y borrado genérico

Visión de conjunto

Con la ayuda del análisis del principio TypeToken, se refuerza la comprensión del borrado genérico, de modo que podamos saber cuándo y cómo obtener tipos genéricos.

Borrado genérico

Como todos sabemos, los genéricos de Java solo son válidos en tiempo de compilación, y este tipo genérico se borrará en tiempo de ejecución, es decir, tanto List como List son en realidad tipos List en tiempo de ejecución.

¿Por qué elegir este mecanismo de implementación? ¿No se puede borrar? Diez años después del nacimiento de Java, quería realizar un concepto similar a las plantillas de C ++, a saber, genéricos. La biblioteca de clases de Java es un activo muy valioso en el ecosistema de Java. Es necesario garantizar la compatibilidad con versiones anteriores (es decir, el código existente y los archivos de clase siguen siendo legales) y la compatibilidad con la migración (el código generalizado y el código no generalizado pueden llamarse entre sí ) basado en lo anterior Con estos dos antecedentes y consideraciones, los diseñadores de Java adoptaron una implementación comprometida de "borrado de tipo".

Al mismo tiempo, existe un mecanismo de "pozo" que nos impide obtener los tipos específicos de parámetros genéricos a voluntad durante la operación.

TypeToken

usar

Los estudiantes que han usado Gson saben que es necesario definir un tipo TypeToken al deserializar, como este

private Type type = new TypeToken<List<Map<String, Foo>>>(){}.getType();

//调用fromJson方法时把type传过去,如果type的类型和json保持一致,则可以反序列化出来
gson.fromJson(json, type);

Tres preguntas
¿Por qué utilizar TypeToken para definir el tipo de deserialización? Como se mencionó anteriormente, si el tipo de List <Map <String, Foo >> se pasa directamente, pero debido a que el tipo genérico se borra en tiempo de ejecución, el resultado es en realidad una List, entonces el siguiente Gson no sabe que debe convertirse al tipo Map <String, Foo>, luego Gson usará por defecto el tipo LinkedTreeMap.

¿Por qué hay llaves {}? Este corsé es la esencia. Como todo el mundo sabe, en la gramática de Java, en este contexto, {} se usa para definir una clase anónima. Esta clase anónima hereda la clase TypeToken, que es una subclase de TypeToken.

¿Por qué utilizar subclases para obtener tipos genéricos? Ésta es la clave de la capacidad de TypeToken para obtener tipos genéricos, un método ingenioso. La idea es así: dado que los tipos genéricos como List se borrarán, entonces si uso una subclase SubList extiende List, ¿se conservará el tipo genérico padre en la JVM? Se ha determinado el tipo genérico de la clase principal que mi subclase necesita heredar. Efectivamente, la JVM guarda esta parte de la información, que se almacena en la información de clase de la subclase, consulte: https: // stackoverflow .com / question / 937933 / where-are-generic-types-stored-in-java-class-files Entonces, ¿cómo obtenemos esta información? Afortunadamente, Java proporciona API:

Type mySuperClass = foo.getClass().getGenericSuperclass();
  Type type = ((ParameterizedType)mySuperClass).getActualTypeArguments()[0];
System.out.println(type);

Analice este código, la anotación del método getGenericSuperClass () de la clase Class es:


Devuelve el tipo que representa la superclase directa de la entidad (clase, interfaz, tipo primitivo o vacío) representada por esta clase. Si la superclase es un tipo parametrizado, el objeto Type devuelto debe reflejar con precisión los parámetros de tipo reales utilizados en el código fuente. El tipo parametrizado que representa la superclase se crea si no se había creado antes. Consulte la declaración de ParameterizedType para conocer la semántica del proceso de creación de tipos parametrizados. Si thisClass representa la clase de objeto, una interfaz, un tipo primitivo o void, se devuelve un valor nulo. Si este objeto representa una clase de matriz, se devuelve el objeto Class que representa la clase de objeto
"
En términos generales, devuelve un objeto ParameterizedType para clases con genéricos, devuelve nulo para Object, interfaces y tipos primitivos, y devuelve Object.class para clases de matriz. ParameterizedType es un tipo Java que representa un tipo con parámetros genéricos. Después de la introducción de genéricos en JDK1.5, todas las clases en Java implementan la interfaz Type y ParameterizedType hereda la interfaz Type. Todas las clases de clases que contienen genéricos implementarán esta interfaz.

Depura tu mismo para saber qué devuelve.

Principio El
método central son las dos oraciones que se acaban de decir, y el resto es muy simple. Veamos el método getType de TypeToken

public final Type getType() {
 //直接返回type
    return type;
  }

Ver la inicialización del tipo

//注意这里用了protected关键字,限制了只有子类才能访问
protected TypeToken() {
    this.type = getSuperclassTypeParameter(getClass());
    this.rawType = (Class<? super T>) $Gson$Types.getRawType(type);
    this.hashCode = type.hashCode();
  }
  
  //getSuperclassTypeParameter方法
  //这几句就是上面的说到
  static Type getSuperclassTypeParameter(Class<?> subclass) {
    Type superclass = subclass.getGenericSuperclass();
    if (superclass instanceof Class) {
      throw new RuntimeException("Missing type parameter.");
    }
    ParameterizedType parameterized = (ParameterizedType) superclass;
    //这里注意一下,返回的是Gson自定义的,在$Gson$Types里面定义的TypeImpl等,这个类都是继承Type的。
    return $Gson$Types.canonicalize(parameterized.getActualTypeArguments()[0]);
  }

para resumir

Después de comprender el principio, creo que todos saben cómo obtener tipos genéricos.

Beneficios del lector

¡Gracias por ver aquí!
He compilado muchas de las últimas preguntas de la entrevista de Java de 2021 (incluidas las respuestas) y notas de estudio de Java aquí, como se muestra a continuación
Inserte la descripción de la imagen aquí

Las respuestas a las preguntas de la entrevista anteriores están organizadas en notas de documentos. Además de las entrevistas, también se recopiló información sobre algunos de los fabricantes y se entrevistó a la última colección 2021 de Zhenti (ambas documentan una pequeña parte de la captura de pantalla) gratis para que todos la compartan, los que lo necesiten pueden hacer clic para ingresar la señal: ¡CSDN! Libre para compartir ~

Si te gusta este artículo, reenvíalo y dale me gusta.

¡Recuerda seguirme!

Supongo que te gusta

Origin blog.csdn.net/weixin_49527334/article/details/115334014
Recomendado
Clasificación