Notas de JVM (12) estructura de archivos de clase

Los archivos de clase son un conjunto de secuencias binarias basadas en bytes 8. Cada elemento de datos está organizado en el archivo en orden estricto y compacto sin ningún separador en el medio, lo que hace que el contenido almacenado en todo el archivo de clase sea casi todos los datos necesarios para el funcionamiento del programa. , no existen lagunas. Cuando encuentre un elemento de datos que deba ocupar más de 8 bytes de espacio, se dividirá en varios 8 bytes para almacenamiento de acuerdo con el primer método de orden superior.

De acuerdo con la "Especificación de máquina virtual de Java", el formato de archivo de clase utiliza una pseudoestructura similar a la estructura del lenguaje C para almacenar datos. Solo hay dos tipos de datos en esta pseudoestructura: "número sin signo" y "tabla". El siguiente análisis debe basarse en estos dos tipos de datos, por lo que estos dos conceptos deben explicarse claramente aquí.

  • Los números sin signo pertenecen a los tipos de datos básicos. U1, u2, u4 y u8 representan números sin signo de 1 byte, 2 bytes, 4 bytes y 8 bytes respectivamente. Los números sin signo se pueden usar para describir números, referencias de índice, valores de cantidad, o formar valores de cadena según la codificación UTF-8.

  • Una tabla es un tipo de datos compuesto por varios números sin signo u otras tablas como elementos de datos. Para facilitar la distinción, el nombre de todas las tablas suele terminar con "_info". Una tabla se utiliza para describir datos con una estructura compuesta con una relación jerárquica. El archivo de clase completo también puede considerarse como una tabla en esencia. Los elementos de datos en esta tabla están dispuestos en orden estricto.

Ya sea un número sin signo o una tabla, cuando es necesario describir múltiples datos del mismo tipo pero con una cantidad indefinida, se suele utilizar en forma de contador de precapacidad más varios elementos de datos consecutivos. , esta serie de elementos de datos continuos se denomina Un tipo de datos es una "colección" de cierto tipo. 

1. La versión del número mágico y el archivo de clase.

Los primeros 4 bytes de cada archivo de Clase se denominan Número Mágico (Magic Number), y su única función es determinar si el archivo es un archivo de Clase que puede ser aceptado por la máquina virtual.

El número mágico del archivo Class es muy "romántico", y el valor es 0xCAFEBABE (¿café bebé?).

Los 4 bytes que siguen al número mágico almacenan el número de versión del archivo de clase: los bytes 5 y 6 son el número de versión secundaria (versión secundaria), y los bytes 7 y 8 son el número de versión principal (versión principal).

El número de versión de Java comienza en 45. Después de JDK 1.1, el número de versión principal de cada versión principal de JDK aumenta en 1 (JDK 1.0~1.1 usa el número de versión de 45.0~45.3), y la versión superior de JDK puede ser compatible con la versión anterior Versión del archivo de clase, pero el archivo de clase de la versión posterior no se puede ejecutar, porque la "Especificación de máquina virtual de Java" requiere claramente en la sección de verificación del archivo de clase que incluso si el formato del archivo no ha cambiado , la máquina virtual también debe negarse a ejecutar el archivo de clase que exceda su número de versión Archivos de clase.

2. Piscina constante

Inmediatamente después de los números de versión principal y secundaria se encuentra la entrada del conjunto de constantes. El conjunto de constantes se puede comparar con el almacén de recursos en el archivo de Clase. Son los datos más asociados con otros elementos en la estructura del archivo de Clase y, por lo general, son los datos elemento que ocupa el mayor espacio en el archivo Clase Uno, además, es el primer dato de tipo tabla que aparece en el archivo Clase.

Dado que el número de constantes en el grupo de constantes no es fijo, se debe colocar un tipo de datos u2 en la entrada del grupo de constantes, que representa el valor de recuento de la capacidad del grupo de constantes (constant_pool_count). A diferencia de la convención de lenguaje en Java, este conteo de capacidad comienza desde 1 en lugar de 0.

Hay dos tipos principales de constantes almacenadas en el conjunto de constantes: referencias literales y simbólicas.

Las cantidades literales están más cerca del concepto constante a nivel del lenguaje Java, como cadenas de texto, valores constantes declarados como finales, etc. Las referencias simbólicas pertenecen al concepto de principios de compilación, incluyendo principalmente los siguientes tipos de constantes:

  • Paquete exportado o abierto por el módulo (Paquete)

  • Nombres completamente calificados de clases e interfaces

  • Nombre de campo y descriptor (Descriptor)

  • nombre del método y descriptor

  • Manejador de método y tipo de método (Manejador de método, Tipo de método, Invocar dinámica)

  • Sitios de llamadas dinámicos y constantes dinámicas (Sitio de llamadas calculado dinámicamente, Constante calculado dinámicamente)

 3. Señal de acceso 

Después del final del conjunto de constantes, los siguientes 2 bytes representan indicadores de acceso (access_flags), que se utilizan para identificar información de acceso a nivel de clase o interfaz, incluidos: si la clase es una clase o una interfaz; si está definida como un tipo público, si se define como un tipo abstracto, si es una clase, si se declara final, etc.

4. Índice de clase, índice de clase principal y colección de índice de interfaz

Tanto el índice de clase (esta_clase) como el índice de clase principal (super_clase) son datos de tipo u2, y el conjunto de índices de interfaz (interfaces) es una colección de datos de tipo u2. Estos tres elementos de datos en el archivo de clase determinan el tipo de la relación de herencia de datos.

El índice de clase se utiliza para determinar el nombre completo de esta clase y el índice de la clase principal se usa para determinar el nombre completo de la clase principal de esta clase. Dado que el lenguaje Java no permite la herencia múltiple, solo hay un índice de clase principal. Excepto java.lang.Object, todas las clases de Java tienen clases principales. Por lo tanto, excepto java.lang.Object, los índices de clase principal de todas las clases de Java las clases son no es 0. La colección de índice de interfaz se usa para describir qué interfaces implementa esta clase. Estas interfaces implementadas seguirán el orden de las interfaces después de la palabra clave implements (si el archivo de clase representa una interfaz, debería ser la palabra clave extends) de izquierda a derecha. la colección de índices de la interfaz.

5. Colección de mesas de campo

La tabla de campos (field_info) se utiliza para describir las variables declaradas en la interfaz o clase. "Field" en el lenguaje Java incluye variables de nivel de clase y variables de nivel de instancia, pero no incluye variables locales declaradas dentro de los métodos.

Los modificadores que un campo puede incluir incluyen el alcance del campo (modificadores públicos, privados, protegidos), si es una variable de instancia o una variable de clase (modificador estático), variabilidad (final) y visibilidad concurrente (modificador volátil, ya sea es obligatorio desde la lectura y escritura de la memoria principal), se puede serializar (modificador transitorio), tipo de datos de campo (tipo básico, objeto, matriz), nombre de campo. En la información anterior, cada modificador es un valor booleano, hay un modificador o no hay modificador, y es adecuado para ser representado por una bandera. El nombre del campo y el tipo de datos del campo no son fijos y solo se pueden describir haciendo referencia a constantes en el conjunto de constantes.

6. Colección de tablas de métodos

Si comprende el contenido de la tabla de campos en la sección anterior, el contenido de la tabla de métodos en esta sección será muy simple. La descripción del método y la descripción del campo en el formato de almacenamiento del archivo de clase son casi completamente consistentes. La estructura de la tabla de métodos es la misma que la de la tabla de campos, incluidas las banderas de acceso (access_flags), el índice de nombres (name_index), el índice descriptor (descriptor_index) ), colección de tablas de atributos (atributos) varios elementos.
El código Java en el método, después de ser compilado en instrucciones de código de bytes por el compilador Javac, se almacena en un atributo denominado "Código" en la colección de tablas de atributos del método. La tabla de atributos es la información más extensible en el formato de archivo de clase. proyecto.

7. Colección de tablas de propiedades

Los archivos de clases, las tablas de campos y las tablas de métodos pueden llevar su propio conjunto de tablas de atributos para describir información específica para ciertos escenarios.

A diferencia de otros elementos de datos en el archivo de clase que requieren un orden, una longitud y un contenido estrictos, el conjunto de tablas de propiedades tiene restricciones un poco menos estrictas, no se requiere un orden estricto para cada tabla de propiedades y la "Especificación de máquina virtual de Java" lo permite siempre que no coincide con el existente Si el nombre del atributo se repite, cualquier compilador implementado por cualquier persona puede escribir la información del atributo definida por él mismo en la tabla de atributos, y la máquina virtual Java la ignorará cuando se esté ejecutando.

propiedades. Para analizar correctamente el archivo de clase, la "Especificación de máquina virtual de Java" inicialmente solo predefinió 9 atributos que todas las implementaciones de máquinas virtuales de Java deberían poder reconocer. En la última versión de Java SE 12 de la "Especificación de máquina virtual de Java", el Los atributos de definición predefinidos se han aumentado a 29 elementos.

1.  atributo de código
Después de que el código en el cuerpo del método del programa Java es procesado por el compilador Javac, finalmente se convierte en una instrucción de código de bytes y se almacena en el atributo Código. El atributo Código aparece en el conjunto de atributos de la tabla de métodos, pero no todas las tablas de métodos deben tener este atributo. Por ejemplo, el método en la interfaz o clase abstracta no tiene el atributo Código. Si la tabla de métodos tiene el atributo Código, entonces su estructura se verá así.
  • índice_nombre_atributo 
Es un índice que apunta a una constante de tipo CONSTANT_Utf8_info. El valor constante se fija como "Código", que representa el nombre del atributo del atributo.Attribute_length indica la longitud del valor del atributo. Dado que el índice del nombre del atributo y la longitud del atributo son 6 bytes en total, por lo tanto, la longitud del valor del atributo se fija en la longitud de toda la tabla de atributos menos 6 bytes.
  • max_stack
Representa la profundidad máxima de la pila de operandos (Pila de operandos). En cualquier punto durante la ejecución del método, la pila de operandos nunca excederá esta profundidad. Cuando la máquina virtual se está ejecutando, debe asignar la profundidad de la pila de operaciones en el marco de la pila (marco de la pila) de acuerdo con este valor.
  • max_locals
Representa el espacio de almacenamiento requerido por la tabla de variables locales. Aquí, la unidad de max_locals es la ranura variable (Slot), que es la unidad más pequeña utilizada por la máquina virtual para asignar memoria a las variables locales. Para byte, char, float, int, short, boolean y returnAddress y otros tipos de datos cuya longitud no supere los 32 bits, cada variable local ocupa una ranura de variable, mientras que los dos tipos de datos de 64 bits double y long requieren dos variables Ranura para almacenamiento. Los parámetros del método (incluido el parámetro oculto "this" en el método de instancia), los parámetros del controlador de excepciones explícito (Parámetro del controlador de excepciones, que es la excepción definida en el bloque catch en la instrucción try-catch) y las variables locales definidas en el cuerpo del método, todos necesitan confiar en la tabla de variables locales para almacenar.
Tenga en cuenta que no se trata de cuántas variables locales se usan en el método, la suma de la cantidad de ranuras de variables ocupadas por estas variables locales se usa como el valor de max_locals, la pila de operandos y la tabla de variables locales determinan directamente la memoria consumida por un marco de pila del método, la profundidad innecesaria de la pila de operandos y el número de ranuras variables provocarán un desperdicio de memoria. El método de la máquina virtual Java es reutilizar las ranuras de variables en la tabla de variables locales. Cuando la ejecución del código excede el alcance de una variable local, la ranura de variable ocupada por esta variable local puede ser utilizada por otras variables locales, y Javac El compilador se basará en El ámbito de las variables se utiliza para asignar ranuras de variables para cada variable, y el tamaño de max_locals se calcula de acuerdo con el número máximo y el tipo de variables locales que existen al mismo tiempo.
  • code_length 和 código
Se utiliza para almacenar las instrucciones de código de bytes generadas después de compilar el programa fuente de Java. code_length representa la longitud del código de bytes, y el código es una serie de flujos de bytes utilizados para almacenar instrucciones de código de bytes. Dado que se denomina instrucción de código de bytes, como su nombre lo indica, cada instrucción es un solo byte de tipo u1. Cuando la máquina virtual lee un código de bytes en el código, puede averiguar qué instrucción representa el código de bytes y usted puede saber si los parámetros deben ir seguidos de esta instrucción y cómo deben analizarse los parámetros subsiguientes. Sabemos que el rango de valores de un tipo de datos u1 es 0x00~0xFF, correspondiente a 0~255 en decimal, es decir, se pueden expresar un total de 256 instrucciones.
Con respecto a code_length, hay una cosa que vale la pena señalar, aunque es un valor de longitud de tipo u4, el valor máximo teóricamente puede llegar a la 32ª potencia de 2, pero la "Especificación de máquina virtual de Java" limita claramente un método que no permite más de 65535 Instrucciones de código de bytes, es decir, en realidad solo usa la longitud de u 2. Si se excede este límite, el compilador de Javac se negará a compilar.
El atributo Código es el atributo más importante en el archivo Clase. Si la información en un programa Java se divide en código (Código, el código Java en el cuerpo del método) y metadatos (Metadatos, incluidas clases, campos, definiciones de métodos y otra información ) Dos partes, luego en todo el archivo de Clase, el atributo Código se usa para describir el código, y todos los demás elementos de datos se usan para describir los metadatos.
2. Atributo de excepciones

La función del atributo Exceptions es listar las excepciones verificadas (Checked Exceptions) que pueden ser lanzadas en el método, es decir, las excepciones listadas después de la palabra clave throws en la descripción del método.

El elemento número_de_excepciones en este atributo indica que el método puede arrojar tipos de excepciones verificadas número_de_excepciones, y cada excepción verificada está representada por un elemento de tabla de índice_excepción; tabla_índice_excepción es un índice que apunta a una constante CONSTANT_Class_info en el conjunto de constantes, que representa el tipo de la excepción verificada .

3. Propiedad LineNumberTable

El atributo LineNumberTable se utiliza para describir la correspondencia entre el número de línea del código fuente de Java y el número de línea del código de bytes (compensación del código de bytes). No es un atributo obligatorio en tiempo de ejecución, pero se generará en el archivo de Clase de manera predeterminada. Puede usar la opción -g:none o -g:lines en Javac para cancelar o solicitar que se genere esta información. Si elige no generar la propiedad LineNumberTable, el impacto principal en la ejecución del programa es que cuando se lanza una excepción, el número de línea de error no se mostrará en la pila y, al depurar el programa, no podrá establecer puntos de interrupción de acuerdo con el línea de código fuente.

line_number_table es una colección de line_number_table_length y tipo line_number_info. La tabla line_number_info contiene dos elementos de datos de tipo u2, start_pc y line_number. El primero es el número de línea del código de bytes y el segundo es el número de línea del código fuente de Java.

 4. Propiedades LocalVariableTable y LocalVariableTypeTable

El atributo LocalVariableTable se usa para describir la relación entre las variables en la tabla de variables locales en el marco de la pila y las variables definidas en el código fuente de Java. No es un atributo obligatorio en tiempo de ejecución, pero se generará en el archivo de clase mediante predeterminado y se puede usar en las opciones Javac- g:none o -g:vars para suprimir o requerir la generación de esta información. Si no se genera este atributo, el mayor impacto es que cuando otros hagan referencia a este método, todos los nombres de los parámetros se perderán. Por ejemplo, el IDE usará marcadores de posición como arg0 y arg1 para reemplazar los nombres de los parámetros originales. Esto no tiene ningún efecto. en la ejecución del programa, pero traerá grandes inconvenientes para la escritura de código, y el valor del parámetro no se puede obtener del contexto de acuerdo con el nombre del parámetro durante la depuración.

Los atributos start_pc y longitud representan respectivamente el desplazamiento del código de bytes al comienzo del ciclo de vida de esta variable local y la longitud cubierta por su alcance. La combinación de los dos es el alcance de esta variable local en el código de bytes. Tanto name_index como descriptor_index son índices que apuntan a constantes de tipo CONSTANT_Utf8_info en el conjunto de constantes, que representan respectivamente el nombre de la variable local y el descriptor de la variable local. index es la posición de esta variable local en la ranura de variables en la tabla de variables locales del marco de pila. Cuando el tipo de dato variable es de 64 bits (doble y largo), ocupa dos ranuras variables, índice e índice+1

 5. Atributos SourceFile y SourceDebugExtension

El atributo SourceFile se utiliza para registrar el nombre del archivo de código fuente que genera el archivo de clase. Esta propiedad también es opcional y se puede desactivar o requerir que se genere usando las opciones -g:none o -g:source de Javac. En Java, para la mayoría de las clases, el nombre de la clase y el nombre del archivo son los mismos, pero existen excepciones en algunos casos especiales (como las clases internas). Si no se genera este atributo, cuando se lanza una excepción, el nombre del archivo al que pertenece el código de error no se mostrará en la pila.

6. Propiedad ConstantValue

La función del atributo ConstantValue es notificar a la máquina virtual para que asigne automáticamente valores a las variables estáticas. Solo las variables (variables de clase) modificadas por la palabra clave static pueden usar este atributo. Las definiciones de variables como "int x=123" y "static int x=123" son muy comunes en los programas Java, pero la forma y el momento en que la máquina virtual asigna estas dos variables es diferente. La asignación a variables de tipo no estático (es decir, variables de instancia) se realiza en el método constructor de instancias <init>(); para las variables de clase, hay dos formas de elegir: en el método constructor de clases <clinit>() o use la propiedad ConstantValue.

En la actualidad, la elección del compilador Javac implementado por Oracle es que si usa final y static para modificar una variable (según la costumbre, es más apropiado llamarla "constante" aquí), y el tipo de datos de esta variable es un tipo básico o java.lang.String Si lo es, se generará el atributo ConstantValue para la inicialización, si la variable no se modifica final, o no es un tipo básico y una cadena, se inicializará en el <clinit método >().

7. Propiedad ClasesInteriores

El atributo InnerClasses se usa para registrar la asociación entre la clase interna y la clase anfitriona. Si se define una clase interna en una clase, el compilador generará el atributo InnerClasses para ella y las clases internas que contiene.

8. Atributos obsoletos y sintéticos

Tanto los atributos Obsoletos como los Sintéticos pertenecen al atributo booleano del tipo de bandera. Solo hay una diferencia entre sí y no, y no hay un concepto de valor de atributo.

El atributo Obsoleto se usa para indicar que una determinada clase, campo o método ha sido designado como ya no recomendado por el autor del programa. Se puede configurar usando la anotación "@deprecated" en el código.

 9. Propiedad StackMapTable

El atributo StackMapTable se agregó a la especificación del archivo Class en JDK 6. Es un atributo de longitud variable bastante complejo ubicado en la tabla de atributos del atributo Code. Este atributo será verificado por el nuevo validador de verificación de tipo (Tipo

Checker) (consulte el Capítulo 7 sobre la verificación del código de bytes para obtener más detalles), el propósito es reemplazar el verificador de deducción de tipo anterior basado en el análisis del flujo de datos que consume más rendimiento.

Este verificador de verificación de tipos se derivó originalmente del verificador de código de bytes implementado por Sheng Liang (cuyo nombre parece ser un miembro de ascendencia china en el equipo de máquinas virtuales) implementado como JavaME CLDC. Bajo la premisa de asegurar la legalidad de los archivos Class, el nuevo verificador omite el paso de confirmar la legalidad del comportamiento del bytecode a través del análisis de flujo de datos en tiempo de ejecución, y utiliza una serie de tipos de verificación (Verification Type) que se registra directamente en el archivo Class, y el proceso de deducción de tipos se reemplaza por la verificación de estos tipos de verificación, lo que mejora en gran medida el rendimiento de la verificación del código de bytes.

El atributo StackMapTable contiene de cero a más marcos de mapa de pila (marco de mapa de pila), cada marco de mapa de pila representa explícita o implícitamente un desplazamiento de código de bytes, que se usa para representar variables locales cuando se ejecuta el tipo de validación de código de bytes para tablas y pilas de operandos. El verificador de verificación de tipos determinará si una instrucción de código de bytes se ajusta a las restricciones lógicas al verificar los tipos requeridos de las variables locales del método de destino y la pila de operandos.

10. Atributo de firma

El atributo Firma se agregó a la especificación del archivo Clase en JDK 5. Es un atributo opcional de longitud fija que puede aparecer en la tabla de atributos de las estructuras de la tabla de clase, tabla de campo y tabla de método. La gramática del lenguaje Java se ha mejorado mucho en JDK 5. Después de eso, si la firma genérica de cualquier clase, interfaz, método de inicialización o miembro contiene una variable de tipo (Variable de tipo) o un tipo parametrizado (ParameterizedType), la Firma El atributo será Registrar la información de firma genérica para él.

La razón por la cual dicho atributo se usa especialmente para registrar tipos genéricos es porque los genéricos del lenguaje Java usan los pseudo-genéricos implementados por el método de borrado, y toda la información genérica en el bytecode (atributo de código) se compila (variable de tipo, parametrizado tipos) se borran todos después de la compilación. La ventaja de usar el método de borrado es que es simple de implementar (principalmente modifica el compilador de Javac y solo se realizan algunos cambios dentro de la máquina virtual), es muy fácil de implementar Backport y también puede ahorrar espacio en la memoria. ocupado por algunos tipos durante el tiempo de ejecución. Pero la desventaja es que el tiempo de ejecución no puede tratar los tipos genéricos de la misma manera que los tipos comunes definidos por el usuario como C# y otros lenguajes con compatibilidad genérica verdadera. Por ejemplo, la información genérica no se puede obtener durante la reflexión del tiempo de ejecución. El atributo Signature se agregó para compensar este defecto. Ahora, el tipo genérico que puede obtener la API de reflexión de Java, la fuente de datos final también es este atributo.

11. Atributo BootstrapMethods

El atributo BootstrapMethods se agregó a la especificación del archivo de clase en JDK 7. Es un atributo complejo de longitud variable ubicado en la tabla de atributos del archivo de clase. Este atributo se utiliza para contener el calificador del método de arranque al que hace referencia la instrucción invocación dinámica.

De acuerdo con la "Especificación de máquina virtual de Java" (de Java SE 7), si alguna vez apareció una constante de tipo CONSTANT_InvokeDynamic_info en el conjunto de constantes de una determinada estructura de archivo de clase, entonces debe haber una

BootstrapMethods, además, incluso si las constantes de tipo CONSTANT_InvokeDynamic_info aparecen muchas veces en el grupo de constantes, puede haber como máximo un atributo BootstrapMethods en la tabla de atributos del archivo de clase. 

12. Atributo MethodParameters

MethodParameters se agregó recientemente al formato de archivo Class en JDK 8. Es un atributo de longitud variable que se usa en la tabla de métodos. La función de MethodParameters es registrar el nombre y la información de cada parámetro formal del método.

Inicialmente, en función de las consideraciones de espacio de almacenamiento, el archivo de clase no almacena nombres de parámetros de métodos de forma predeterminada, ya que no hay diferencia en el nombre del parámetro para que la computadora ejecute el programa, siempre que tenga el nombre correcto en el código fuente. código. Con la popularidad de Java, esto ha traído muchos inconvenientes a la diseminación y reutilización secundaria del programa.Dado que no hay un nombre de parámetro en el archivo de clase, si solo hay un paquete único sin JavaDoc adjunto, edítelo en el IDE Al utilizar el método en el paquete, es imposible obtener el indicador inteligente de la llamada al método, lo que dificulta la difusión del paquete JAR. Más tarde, "-g:var" se convirtió en el valor predeterminado utilizado por Javac y muchos IDE al compilar Class, lo que generará el nombre del parámetro del método en la propiedad LocalVariableTable.

Este nuevo atributo en JDK 8 permite al compilador escribir el nombre del método en el archivo Class (con el parámetro -parameters agregado en el momento de la compilación), y MethodParameters es un atributo de la tabla de métodos, que está al mismo nivel que el atributo Code. y se puede usar en tiempo de ejecución Obtenido a través de la API de reflexión.

13. Atributos modulares relacionados

Una función de peso pesado de JDK 9 es la función de modularización de Java, porque el archivo de descripción del módulo (module-info.java) finalmente se compila en un archivo de clase independiente para el almacenamiento, por lo que el formato de archivo de clase también se extiende a módulos y paquetes de módulos. Los tres atributos de ModuleMainClass y ModuleMainClass se utilizan para admitir funciones relacionadas con la modularización de Java.

El atributo Módulo es un atributo de longitud variable muy complejo, además de indicar el nombre, la versión y la información de la bandera del módulo, también almacena todos los contenidos definidos por el módulo requiere, exporta, abre, usa y proporciona.

Entre ellos, module_name_index es un valor de índice que apunta a la constante CONSTANT_Utf8_info del grupo de constantes, que representa el nombre del módulo.

module_version_index es un valor de índice que apunta a la constante CONSTANT_Utf8_info del grupo de constantes, que representa el número de versión del módulo.

Cada elemento del atributo de exportaciones representa un paquete exportado por el módulo, y el índice_exportaciones es un valor de índice que apunta a la constante CONSTANT_Package_info del grupo de constantes, que representa el paquete exportado por el módulo.

export_to_count es el contador limitado del paquete de exportación, si el contador es cero, significa que el paquete de exportación es Unqualified, es decir, está completamente abierto y cualquier otro módulo puede acceder a todo el contenido del paquete.

ModulePackages es otro atributo de longitud variable que se usa para admitir la modularización de Java.Se usa para describir todos los paquetes en el módulo, ya sea que se exporten o se abran.

package_count es el contador de la matriz package_index, y cada elemento en package_index es un valor de índice que apunta a la constante CONSTANT_Package_info del grupo de constantes, que representa un paquete en el módulo actual.

El último atributo ModuleMainClass es un atributo de longitud fija que se utiliza para determinar la clase principal del módulo (Main Class).

14. Anotar propiedades relacionadas en tiempo de ejecución

Ya en el período JDK 5, se mejoró la sintaxis del lenguaje Java, una de las cuales es brindar soporte para anotaciones (Annotation). Para almacenar información de anotaciones en el código fuente, la sincronización de archivos de clase agrega RuntimeVisibleAnnotations,

RuntimeInvisibleAnnotations, RuntimeVisibleParameterAnnotations y RuntimeInvisibleParameterAnnotations cuatro propiedades. En el período JDK 8, el alcance de las anotaciones en el lenguaje Java se mejoró aún más y se agregaron anotaciones de tipo (JSR 308). Por lo tanto, también se agregaron dos atributos, RuntimeVisibleTypeAnnotations y RuntimeInvisibleTypeAnnotations, al archivo de clase. Dado que estos seis atributos son similares en estructura y función, los fusionamos e presentamos RuntimeVisibleAnnotations como representante.

RuntimeVisibleAnnotations es un atributo de longitud variable que registra anotaciones visibles en tiempo de ejecución en la declaración de una clase, campo o método.Cuando usamos la API de reflexión para obtener anotaciones en una clase, campo o método, el valor de retorno se obtiene a través de este atributo de.

Supongo que te gusta

Origin blog.csdn.net/socct_yj/article/details/129962553
Recomendado
Clasificación