El estilo de vida del archivo de clase Java

Bienvenidos a otra entrega de "Under the Hood". En el artículo del mes pasado hablé de la máquina virtual Java, o JVM, la computadora abstracta para la que se compilan todos los programas Java. Si no está familiarizado con la JVM, es posible que desee leer el artículo del mes pasado antes de este. En este artículo, proporciono un vistazo a la estructura básica y el estilo de vida del archivo de clase Java.

Nacido para viajar

El archivo de clases de Java es un formato definido con precisión para Java compilado. El código fuente de Java se compila en archivos de clase que cualquier JVM puede cargar y ejecutar. Los archivos de clases pueden viajar a través de una red antes de ser cargados por la JVM.

De hecho, si está leyendo este artículo a través de un navegador compatible con Java, los archivos de clase para el subprograma de simulación al final del artículo están volando a través de Internet a su computadora en este momento. Si desea escucharlos (y su computadora tiene capacidad de audio), presione el siguiente botón:

Necesita un navegador compatible con Java para ver este subprograma

Parece que se están divirtiendo, ¿eh? Eso está en su naturaleza. Los archivos de clases de Java fueron diseñados para viajar bien. Son independientes de la plataforma, por lo que serán bienvenidos en más lugares. Contienen códigos de bytes, el conjunto de instrucciones compacto para la JVM, por lo que pueden viajar con poco peso. Los archivos de clase Java están constantemente pasando por las redes a una velocidad vertiginosa para llegar a las JVM de todo el mundo.

¿Qué hay en un archivo de clase?

El archivo de clase Java contiene todo lo que una JVM necesita saber sobre una clase o interfaz Java. En su orden de aparición en el archivo de clase, los componentes principales son: magia, versión, grupo constante, indicadores de acceso, esta clase, superclase, interfaces, campos, métodos y atributos.

La información almacenada en el archivo de clase a menudo varía en longitud, es decir, la longitud real de la información no se puede predecir antes de cargar el archivo de clase. Por ejemplo, el número de métodos enumerados en el componente de métodos puede diferir entre los archivos de clase, porque depende del número de métodos definidos en el código fuente. Dicha información se organiza en el archivo de clase anteponiendo la información real por su tamaño o longitud. De esta forma, cuando la JVM carga la clase, primero se lee el tamaño de la información de longitud variable. Una vez que la JVM conoce el tamaño, puede leer correctamente la información real.

La información generalmente se escribe en el archivo de la clase sin espacio ni relleno entre piezas consecutivas de información; todo está alineado en los límites de bytes. Esto ayuda a que los archivos de clase sean pequeños para que sean aerodinámicos a medida que vuelan por las redes.

El orden de los componentes del archivo de clase está estrictamente definido para que las JVM puedan saber qué esperar y dónde esperarlo al cargar un archivo de clase. Por ejemplo, cada JVM sabe que los primeros ocho bytes de un archivo de clase contienen los números mágicos y de versión, que el grupo de constantes comienza en el noveno byte y que los indicadores de acceso siguen al grupo de constantes. Pero debido a que el grupo constante es de longitud variable, no sabe el paradero exacto de las banderas de acceso hasta que haya terminado de leer en el grupo constante. Una vez que ha terminado de leer en el grupo constante, sabe que los dos bytes siguientes serán las banderas de acceso.

Números de versión y magia

Los primeros cuatro bytes de cada archivo de clase son siempre 0xCAFEBABE. Este número mágico hace que los archivos de clase Java sean más fáciles de identificar, porque hay pocas probabilidades de que los archivos que no pertenecen a la clase comiencen con los mismos cuatro bytes iniciales. El número se llama mágico porque los diseñadores de formato de archivo pueden sacarlo de un sombrero. El único requisito es que no esté siendo utilizado por otro formato de archivo que pueda encontrarse en el mundo real. Según Patrick Naughton, un miembro clave del equipo original de Java, el número mágico se eligió "mucho antes de que se pronunciara el nombre Java en referencia a este lenguaje. Estábamos buscando algo divertido, único y fácil de recordar. Es sólo una coincidencia que OxCAFEBABE, una referencia indirecta a los simpáticos baristas de Peet's Coffee, presagiara el nombre de Java ".

Los segundos cuatro bytes del archivo de clase contienen los números de versión mayor y menor. Estos números identifican la versión del formato de archivo de clase al que se adhiere un archivo de clase en particular y permiten que las JVM verifiquen que el archivo de clase se puede cargar. Cada JVM tiene una versión máxima que puede cargar y las JVM rechazarán los archivos de clase con versiones posteriores.

Piscina constante

El archivo de clase almacena constantes asociadas con su clase o interfaz en el grupo de constantes. Algunas constantes que se pueden ver retozando en el grupo son cadenas literales, valores finales de variables, nombres de clases, nombres de interfaces, nombres y tipos de variables y nombres y firmas de métodos. La firma de un método es su tipo de retorno y su conjunto de tipos de argumentos.

El grupo de constantes está organizado como una matriz de elementos de longitud variable. Cada constante ocupa un elemento en la matriz. A lo largo del archivo de clase, las constantes son referidas por el índice entero que indica su posición en la matriz. La constante inicial tiene un índice de uno, la segunda constante tiene un índice de dos, etc. La matriz de grupo de constantes está precedida por su tamaño de matriz, por lo que las JVM sabrán cuántas constantes esperar al cargar el archivo de clase.

Cada elemento del grupo de constantes comienza con una etiqueta de un byte que especifica el tipo de constante en esa posición en la matriz. Una vez que una JVM toma e interpreta esta etiqueta, sabe lo que sigue a la etiqueta. Por ejemplo, si una etiqueta indica que la constante es una cadena, la JVM espera que los dos bytes siguientes tengan la longitud de la cadena. Después de esta longitud de dos bytes, la JVM espera encontrar el número de bytes de longitud , que componen los caracteres de la cadena.

En el resto del artículo, a veces me referiré al enésimo elemento de la matriz de grupo constante como grupo_constante [n]. Esto tiene sentido en la medida en que el conjunto de constantes esté organizado como una matriz, pero tenga en cuenta que estos elementos tienen diferentes tamaños y tipos y que el primer elemento tiene un índice de uno.

Banderas de acceso

Los primeros dos bytes después del grupo constante, las banderas de acceso, indican si este archivo define o no una clase o una interfaz, si la clase o interfaz es pública o abstracta, y (si es una clase y no una interfaz) si la clase es final.

Esta clase

Los siguientes dos bytes, el componente de esta clase , son un índice en la matriz de grupo constante. La constante a la que hace referencia esta clase , constant_pool [this_class], tiene dos partes, una etiqueta de un byte y un índice de nombre de dos bytes. La etiqueta será igual a CONSTANT_Class, un valor que indica que este elemento contiene información sobre una clase o interfaz. Constant_pool [name_index] es una cadena constante que contiene el nombre de la clase o interfaz.

El componente de esta clase proporciona una idea de cómo se usa el grupo constante. Esta clase en sí misma es solo un índice del grupo constante. Cuando una JVM busca constant_pool [this_class], encuentra un elemento que se identifica como CONSTANT_Class con su etiqueta. La JVM sabe que los elementos CONSTANT_Class siempre tienen un índice de dos bytes en el grupo constante, llamado índice de nombre, después de su etiqueta de un byte. Así que busca constant_pool [name_index] para obtener la cadena que contiene el nombre de la clase o interfaz.

Super clase

Después de la esta clase de componentes es la superclase de componentes, otro índice de dos bytes en la piscina constante. Constant_pool [super_class] es un elemento CONSTANT_Class que apunta al nombre de la superclase de la que desciende esta clase.

Interfaces

El componente de interfaces comienza con un recuento de dos bytes del número de interfaces implementadas por la clase (o interfaz) definida en el archivo. Inmediatamente después hay una matriz que contiene un índice en el grupo constante para cada interfaz implementada por la clase. Cada interfaz está representada por un elemento CONSTANT_Class en el grupo constante que apunta al nombre de la interfaz.

Campos

El componente de campos comienza con un recuento de dos bytes del número de campos en esta clase o interfaz. Un campo es una instancia o variable de clase de la clase o interfaz. Después del recuento hay una matriz de estructuras de longitud variable, una para cada campo. Cada estructura revela información sobre un campo, como el nombre del campo, el tipo y, si es una variable final, su valor constante. Parte de la información está contenida en la estructura misma, y ​​parte está contenida en ubicaciones de agrupaciones constantes señaladas por la estructura.

Los únicos campos que aparecen en la lista son aquellos que fueron declarados por la clase o interfaz definida en el archivo; no aparecen en la lista campos heredados de superclases o superinterfaces.

Métodos

El componente de métodos comienza con un recuento de dos bytes del número de métodos en la clase o interfaz. Este recuento incluye solo los métodos que están definidos explícitamente por esta clase, no los métodos que puedan heredarse de las superclases. Siguiendo el recuento de métodos están los métodos en sí.

La estructura de cada método contiene varias piezas de información sobre el método, incluido el descriptor del método (su tipo de retorno y lista de argumentos), el número de palabras de pila requeridas para las variables locales del método, el número máximo de palabras de pila requeridas para el operando del método pila, una tabla de excepciones capturadas por el método, la secuencia de código de bytes y una tabla de números de línea.

Atributos

En la parte trasera están los atributos, que brindan información general sobre la clase o interfaz particular definida por el archivo. La sección de atributos tiene un recuento de dos bytes del número de atributos, seguido de los propios atributos. Por ejemplo, un atributo es el atributo del código fuente; revela el nombre del archivo fuente a partir del cual se compiló este archivo de clase. Las JVM ignorarán silenciosamente cualquier atributo que no reconozcan.

Cargando: una simulación de un archivo de clase que llega a su destino JVM

El siguiente subprograma simula una JVM que carga un archivo de clase. El archivo de clase que se está cargando en la simulación fue generado por el compilador javac dado el siguiente código fuente de Java:

class Act {public static void doMathForever () {int i = 0; while (verdadero) {i + = 1; i * = 2; }}}

El fragmento de código anterior proviene del artículo del mes pasado sobre la JVM. Es el mismo método doMathForever () ejecutado por el subprograma EternalMath del artículo del mes pasado. Elegí este código para proporcionar un ejemplo real que no fuera demasiado complejo. Aunque el código puede no ser muy útil en el mundo real, se compila en un archivo de clase real, que se carga mediante la siguiente simulación.

El subprograma GettingLoaded le permite conducir la simulación de carga de clases paso a paso. Para cada paso del camino, puede leer sobre el siguiente fragmento de bytes que está a punto de ser consumido e interpretado por la JVM. Simplemente presione el botón "Paso" para que la JVM consuma el siguiente fragmento. Si presiona "Atrás", se deshará el paso anterior, y si presiona "Restablecer", la simulación volverá a su estado original, lo que le permitirá comenzar de nuevo desde el principio.

La JVM se muestra en la parte inferior izquierda consumiendo el flujo de bytes que forma el archivo de clase Act.class. Los bytes se muestran en flujo hexadecimal desde un servidor en la parte inferior derecha. Los bytes viajan de derecha a izquierda, entre el servidor y la JVM, un fragmento a la vez. La porción de bytes que consumirá la JVM en la siguiente pulsación del botón "Paso" se muestra en rojo. Estos bytes resaltados se describen en el área de texto grande arriba de la JVM. Los bytes restantes más allá del siguiente fragmento se muestran en negro.

Intenté explicar completamente cada fragmento de bytes en el área de texto. Por lo tanto, hay muchos detalles en el área de texto y es posible que desee hojear todos los pasos primero para obtener una idea general y luego mirar hacia atrás para obtener más detalles.

Feliz clic.

Necesita un navegador compatible con Java para ver este subprograma.

Haga clic aquí para obtener el código fuente de GettingLoaded. Para ejecutar este applet por su cuenta, también necesitará los dos archivos que este applet recupera del servidor, el archivo ASCII que contiene el texto de cada paso y el archivo Act.class en sí. Haga clic aquí para obtener el código fuente del subprograma de audio Flying Class Files.

NOTA FINAL: La letra pequeña: "The Java Class File Lifestyle" Artículo Copyright (c) 1996 Bill Venners. Todos los derechos reservados. Applet "GettingLoaded" Copyright (c) 1996 Artima Software Company. Todos los derechos reservados.

: END_ENDNOTE

Bill Venners es presidente de Artima Software Company. A través de Artima, realiza consultoría y desarrollo de software personalizado.

Más información sobre este tema

  • La especificación de la máquina virtual de Java, la palabra oficial de Sun.

    //java.sun.com/1.0alpha3/doc/vmspec/vmspec_1.html

  • Cuando se publique , el libro The Java Virtual Machine Specification , //www.aw.com/cp/lindholm-yellin.html, de Tim Lindholm y Frank Yellin (ISBN 0-201-63452-X), parte de The Java Series, //www.aw.com/cp/javaseries.html), de Addison-Wesley, probablemente será el mejor recurso de JVM.
  • Un borrador del capítulo 4 de la Especificación de la máquina virtual Java , que describe el formato de archivo de clase y el verificador de código de bytes, se puede recuperar de JavaSoft.

    //java.sun.com/java.sun.com/newdocs.html

Esta historia, "El estilo de vida de los archivos de clases de Java" fue publicada originalmente por JavaWorld.