Archivo de clase Java

SeccionesEditar

Hay 10 secciones básicas para la estructura del archivo de clase Java:

  • Número mágico: 0xCAFEBABE
  • Formato de la versión del archivo de clase: las versiones menores y mayores del archivo de clase
  • Pool de constantes: Pool de constantes para la clase
  • Banderas de acceso: por ejemplo si la clase es abstracta, estática, etc.
  • Esta clase: El nombre de la clase actual
  • Superclase: El nombre de la superclase
  • Interfaces: Cualquier interfaz en la clase
  • Campos: Cualquier campo en la clase
  • Métodos: Cualquier método de la clase
  • Atributos: Cualquier atributo de la clase (por ejemplo el nombre del archivo fuente, etc.)

Magic NumberEdit

Los archivos de la clase se identifican por la siguiente cabecera de 4 bytes (en hexadecimal): CA FE BA BE (las 4 primeras entradas de la tabla de abajo). La historia de este número mágico la explicó James Gosling refiriéndose a un restaurante de Palo Alto:

«Solíamos ir a comer a un lugar llamado St Michael’s Alley. Según la leyenda local, en un pasado muy oscuro, los Grateful Dead solían actuar allí antes de triunfar. Era un lugar bastante funky que era definitivamente un Grateful Dead Kinda Place. Cuando Jerry murió, incluso pusieron un pequeño santuario de estilo budista. Cuando solíamos ir allí, nos referíamos al lugar como el Café Dead. En algún momento se notó que era un número HEX. Estaba renovando un código de formato de archivo y necesitaba un par de números mágicos: uno para el archivo de objetos persistentes y otro para las clases. Utilicé CAFEDEAD para el formato del archivo de objetos, y al buscar palabras hexadecimales de 4 caracteres que encajaran después de «CAFE» (parecía ser un buen tema) di con BABE y decidí utilizarlo. Así que CAFEBABE se convirtió en el formato de archivo de clase, y CAFEDEAD fue el formato de objeto persistente. Pero la facilidad de objetos persistentes desapareció, y junto con ella se fue el uso de CAFEDEAD – fue eventualmente reemplazado por RMI.

Diseño generalEditar

Debido a que el archivo de clase contiene elementos de tamaño variable y no contiene también offsets de archivo incrustados (o punteros), es típicamente analizado secuencialmente, desde el primer byte hacia el final. En el nivel más bajo, el formato del archivo se describe en términos de algunos tipos de datos fundamentales:

  • u1: un entero de 8 bits sin signo
  • u2: un entero de 16 bits sin signo en orden de bytes big-endian
  • u4: un entero de 32 bits sin signo en orden de bytes big-endian
  • tabla: una matriz de elementos de longitud variable de algún tipo. El número de elementos de la tabla se identifica mediante un número de conteo precedente (el conteo es un u2), pero el tamaño en bytes de la tabla sólo puede determinarse examinando cada uno de sus elementos.

Algunos de estos tipos fundamentales se reinterpretan luego como valores de nivel superior (como cadenas o números de punto flotante), dependiendo del contexto.No se aplica la alineación de palabras, por lo que nunca se utilizan bytes de relleno.La disposición general del archivo de clase es la que se muestra en la siguiente tabla.

desplazamiento de bytes tamaño tipo o valor descripción
0 4 bytes u1 =
0xCA hex
número mágico (CAFEBABE) utilizado para identificar el archivo como conforme al formato de archivo de clase
1 u1 =
0xFE hex
2 u1 =
0xBA hex
3 u1 =
0xBE hex
4 2 bytes u2 número de versión menor del
5
6 2 bytes u2 número de versión mayor del formato de archivo de clase utilizado.

Java SE 17 = 61 (0x3D hex),
Java SE 16 = 60 (0x3C hex),
Java SE 15 = 59 (0x3B hex),
Java SE 14 = 58 (0x3A hex),
Java SE 13 = 57 (0x39 hex),
Java SE 12 = 56 (0x38 hex),
Java SE 11 = 55 (0x37 hex),
Java SE 10 = 54 (0x36 hex),
Java SE 9 = 53 (0x35 hex),
Java SE 8 = 52 (0x34 hex),
Java SE 7 = 51 (0x33 hex),
Java SE 60 = 50 (0x32 hex),
Java SE 5.0 = 49 (0x31 hex),
JDK 1.4 = 48 (0x30 hex),
JDK 1.3 = 47 (0x2F hex),
JDK 1.2 = 46 (0x2E hex),
JDK 1.1 = 45 (0x2D hex).
Para los detalles de los números de versiones anteriores, véase la nota 1 en The JavaTM Virtual Machine Specification 2nd edition

7
8 2 bytes u2 constant pool count, número de entradas en la siguiente tabla de pool constante. Este conteo es al menos uno mayor que el número real de entradas; ver la siguiente discusión.
9
10 cpsize (variable) tabla tabla de constantes, un array de entradas de constantes de tamaño variable, que contiene elementos como números literales, cadenas y referencias a clases o métodos. Indexado comenzando en 1, conteniendo (conteo de pool constante – 1) número de entradas en total (ver nota).
10+cpsize 2 bytes u2 banderas de acceso, una máscara de bits
11+cpsize
12+cpsize 2 bytes u2 identifica esta clase, índice en el pool de constantes a una entrada de tipo «Class»
13+cpsize
14+cpsize 2 bytes u2 identifica la superclase, índice en el pool de constantes a una entrada de tipo «Clase»
15+cpsize
16+cpsize 2 bytes u2 cuenta de interfaces, número de entradas en la siguiente tabla de interfaces
17+cpsize
18+cpsize isize (variable) table tabla de interfaces: una matriz de longitud variable de índices constantes de pool que describen las interfaces implementadas por esta clase
18+cpsize+isize 2 bytes u2 conteo de campos, número de entradas en la siguiente tabla de campos
19+cpsize+isize
20+cpsize+isize fsize (variable) tabla de campos, matriz de longitud variable de campos

cada elemento es una estructura field_info definida en https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.5

20+cpsize+isize+fsize 2 bytes u2 cuenta de métodos, número de entradas en la siguiente tabla de métodos
21+cpsize+isize+fsize
22+cpsize+isize+fsize mesa (variable) tabla tabla de métodos, matriz de longitud variable de métodos

cada elemento es una estructura method_info definida en https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.6

22+cpsize+isize+fsize+msize 2 bytes u2 cuenta de atributos, número de entradas en la siguiente tabla de atributos
23+cpsize+isize+fsize+msize
24+cpsize+isize+fsize+msize tabla (variable) tabla de atributos, matriz de longitud variable de atributos

cada elemento es una estructura attribute_info definida en https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.7

Representación en un lenguaje de programación tipo CEditar

Dado que C no admite matrices de longitud variable múltiple dentro de una estructura, el código siguiente no compilará y sólo sirve como demostración.

struct Class_File_Format { u4 magic_number; u2 minor_version; u2 major_version; u2 constant_pool_count; cp_info constant_pool; u2 access_flags; u2 this_class; u2 super_class; u2 interfaces_count; u2 interfaces; u2 fields_count; field_info fields; u2 methods_count; method_info methods; u2 attributes_count; attribute_info attributes;}

El pool de constantesEditar

La tabla de pool de constantes es donde se almacenan la mayoría de los valores constantes literales. Esto incluye valores como números de todo tipo, cadenas, nombres de identificadores, referencias a clases y métodos, y descriptores de tipo. Todos los índices, o referencias, a constantes específicas en la tabla de constantes están dadas por números de 16 bits (tipo u2), donde el valor del índice 1 se refiere a la primera constante en la tabla (el valor del índice 0 no es válido).

Debido a decisiones históricas hechas durante el desarrollo del formato del archivo, el número de constantes en la tabla de constantes no es realmente el mismo que el conteo de constantes que precede a la tabla. En primer lugar, la tabla está indexada a partir de 1 (en lugar de 0), pero el recuento debe interpretarse como el índice máximo más uno. Además, dos tipos de constantes (longs y doubles) ocupan dos ranuras consecutivas en la tabla, aunque la segunda ranura de este tipo es un índice fantasma que nunca se utiliza directamente.

El tipo de cada elemento (constante) en el pool de constantes se identifica mediante una etiqueta de bytes inicial. El número de bytes que siguen a esta etiqueta y su interpretación dependen entonces del valor de la etiqueta. Los tipos de constantes válidos y sus valores de etiqueta son:

Tag byte Bytes adicionales Descripción de la constante Versión introducida
1 2+x bytes
(variable)
Cadena UTF-8 (Unicode): una cadena de caracteres prefijada por un número de 16 bits (tipo u2) que indica el número de bytes de la cadena codificada que sigue inmediatamente (que puede ser diferente del número de caracteres). Tenga en cuenta que la codificación utilizada no es realmente UTF-8, sino que implica una ligera modificación de la forma de codificación estándar de Unicode. 1.0.2
3 4 bytes Integer: un número de complemento a dos de 32 bits con signo en formato big-endian 1.0.2
4 4 bytes Float: un número de punto flotante de 32 bits de precisión simple IEEE 754 1,0.2
5 8 bytes Long: un número con signo de complemento a dos de 64 bits en formato big-endian (ocupa dos ranuras en la tabla de pool de constantes) 1,0.2
6 8 bytes Doble: un número de punto flotante de 64 bits de doble precisión IEEE 754 (ocupa dos ranuras en la tabla de agrupación de constantes) 1,0.2
7 2 bytes Referencia de clase: un índice dentro del pool de constantes a una cadena UTF-8 que contiene el nombre completo de la clase (en formato interno) (big-endian) 1.0.2
8 2 bytes Referencia de cadena: un índice dentro del conjunto de constantes a una cadena UTF-8 (big-endian también) 1.0.2
9 4 bytes Referencia de campo: dos índices dentro del pool de constantes, el primero apuntando a una referencia de Clase, el segundo a un descriptor de Nombre y Tipo. (big-endian) 1.0.2
10 4 bytes Referencia de método: dos índices dentro del conjunto de constantes, el primero apuntando a una referencia de Clase, el segundo a un descriptor de Nombre y Tipo. (big-endian) 1.0.2
11 4 bytes Referencia de método de interfaz: dos índices dentro del conjunto de constantes, el primero apuntando a una referencia de Clase, el segundo a un descriptor de Nombre y Tipo. (big-endian) 1.0.2
12 4 bytes Descriptor de nombre y tipo: dos índices a cadenas UTF-8 dentro del conjunto de constantes, el primero representando un nombre (identificador) y el segundo un descriptor de tipo especialmente codificado. 1.0.2
15 3 bytes Method handle: esta estructura se utiliza para representar un handle de método y consiste en un byte de descriptor de tipo, seguido de un índice dentro del pool de constantes. 7
16 2 bytes Tipo de método: esta estructura se utiliza para representar un tipo de método, y consiste en un índice dentro del pool de constantes. 7
17 4 bytes Dinámica: se utiliza para especificar una constante calculada dinámicamente producida por la invocación de un método bootstrap. 11
18 4 bytes InvokeDynamic: lo utiliza una instrucción invokedynamic para especificar un método bootstrap, el nombre de la invocación dinámica, los tipos de argumento y retorno de la llamada y, opcionalmente, una secuencia de constantes adicionales denominadas argumentos estáticos del método bootstrap. 7
19 2 bytes Módulo: se utiliza para identificar un módulo. 9
20 2 bytes Paquete: se utiliza para identificar un paquete exportado o abierto por un módulo. 9

Sólo hay dos tipos constantes integrales, integer y long. Otros tipos integrales que aparecen en el lenguaje de alto nivel, como boolean, byte y short deben representarse como una constante entera.

Los nombres de las clases en Java, cuando se califican completamente, tradicionalmente se separan con puntos, como «java.lang.Object». Sin embargo, dentro de las constantes de referencia de clase de bajo nivel, aparece una forma interna que utiliza barras inclinadas en su lugar, como «java/lang/Object».

Las cadenas Unicode, a pesar del apelativo «cadena UTF-8», no están realmente codificadas según el estándar Unicode, aunque es similar. Hay dos diferencias (véase UTF-8 para una discusión completa). La primera es que el punto de código U+0000 se codifica como la secuencia de dos bytes C0 80 (en hexadecimal) en lugar de la codificación estándar de un solo byte 00. La segunda diferencia es que los caracteres suplementarios (los que están fuera del BMP en U+10000 y superiores) se codifican utilizando una construcción de par de sustitutos similar a UTF-16 en lugar de codificarse directamente con UTF-8. En este caso, cada uno de los dos sustitutos se codifica por separado en UTF-8. Por ejemplo, U+1D11E se codifica como la secuencia de 6 bytes ED A0 B4 ED B4 9E, en lugar de la codificación UTF-8 correcta de 4 bytes de F0 9D 84 9E.

Deja una respuesta

Tu dirección de correo electrónico no será publicada.