Arquivo de classe Java - Java class file
Tipo de mídia da Internet | aplicativo / java-vm, aplicativo / x-httpd-java |
---|---|
Desenvolvido por | Sun Microsystems |
Um arquivo de classe Java é um arquivo (com a extensão de nome de arquivo .class ) contendo bytecode Java que pode ser executado na Java Virtual Machine (JVM) . Um arquivo de classe Java geralmente é produzido por um compilador Java a partir de arquivos de origem da linguagem de programação Java ( arquivos .java ) contendo classes Java (como alternativa, outras linguagens JVM também podem ser usadas para criar arquivos de classe). Se um arquivo de origem tiver mais de uma classe, cada classe será compilada em um arquivo de classe separado.
As JVMs estão disponíveis para muitas plataformas e um arquivo de classe compilado em uma plataforma será executado em uma JVM de outra plataforma. Isso torna os aplicativos Java independentes da plataforma .
História
Em 11 de dezembro de 2006, o formato do arquivo de classe foi modificado em Java Specification Request (JSR) 202.
Layout e estrutura do arquivo
Seções
Existem 10 seções básicas para a estrutura do arquivo de classe Java:
- Número mágico : 0xCAFEBABE
- Versão do formato de arquivo de classe : as versões secundária e principal do arquivo de classe
- Pool constante : pool de constantes para a classe
- Sinalizadores de acesso : por exemplo, se a classe é abstrata, estática, etc.
- Esta classe : o nome da classe atual
- Superclasse : o nome da superclasse
- Interfaces : quaisquer interfaces da classe
- Campos : quaisquer campos da classe
- Métodos : quaisquer métodos da classe
- Atributos : quaisquer atributos da classe (por exemplo, o nome do arquivo-fonte, etc.)
Número mágico
Os arquivos de classe são identificados pelo seguinte cabeçalho de 4 bytes (em hexadecimal ): (as primeiras 4 entradas na tabela abaixo). A história deste número mágico foi explicada por James Gosling referindo-se a um restaurante em Palo Alto :
CA FE BA BE
"Costumávamos almoçar em um lugar chamado St Michael's Alley. De acordo com a lenda local, no passado obscuro, os Grateful Dead costumavam se apresentar lá antes de se tornarem grandes. Era um lugar bem descolado que era definitivamente um Grateful Dead Kinda Place. Quando Jerry morreu, eles até ergueram um pequeno santuário budista. Quando costumávamos ir lá, nos referíamos ao lugar como Café Dead. Em algum lugar ao longo da linha, percebeu-se que era um número HEX. estava reformulando algum código de formato de arquivo e precisava de alguns números mágicos : um para o arquivo de objeto persistente e outro para classes. Usei CAFEDEAD para o formato de arquivo de objeto e no grepping para palavras hexadecimais de 4 caracteres que cabem depois de "CAFE "(parecia ser um bom tema) Eu bati no BABE e decidi usá-lo. Naquela época, não parecia muito importante ou destinado a ir a qualquer lugar a não ser a lata de lixo da história. Então CAFEBABE se tornou o arquivo da classe formato, e CAFEDEAD era o formato de objeto persistente. Mas a facilidade de objeto persistente falhou sim, e junto com ele foi o uso do CAFEDEAD - ele foi eventualmente substituído pelo RMI .
Layout geral
Como o arquivo de classe contém itens de tamanho variável e também não contém deslocamentos de arquivo embutidos (ou ponteiros), ele é normalmente analisado sequencialmente, do primeiro byte até o final. No nível mais baixo, o formato do arquivo é descrito em termos de alguns tipos de dados fundamentais:
- u1 : um inteiro sem sinal de 8 bits
- u2 : um inteiro sem sinal de 16 bits na ordem de bytes big-endian
- u4 : um inteiro não assinado de 32 bits na ordem de bytes big-endian
- tabela : uma matriz de itens de comprimento variável de algum tipo. O número de itens na tabela é identificado por um número de contagem precedente (a contagem é u2), mas o tamanho em bytes da tabela só pode ser determinado examinando cada um de seus itens.
Alguns desses tipos fundamentais são então reinterpretados como valores de nível superior (como strings ou números de ponto flutuante), dependendo do contexto. Não há imposição de alinhamento de palavras e, portanto, nenhum byte de preenchimento é usado. O layout geral do arquivo de classe é mostrado na tabela a seguir.
deslocamento de byte | Tamanho | tipo ou valor | Descrição |
---|---|---|---|
0 | 4 bytes | u1 = 0xCA hex |
número mágico (CAFEBABE) usado para identificar o arquivo em conformidade com o formato de arquivo da classe |
1 | u1 = 0xFE hex |
||
2 | u1 = 0xBA hex |
||
3 | u1 = 0xBE hex |
||
4 | 2 bytes | u2 | número da versão secundária do formato de arquivo da classe que está sendo usado |
5 | |||
6 | 2 bytes | u2 | número da versão principal do formato de arquivo de classe que está sendo usado. Java SE 17 = 61 (0x3D hex), |
7 | |||
8 | 2 bytes | u2 | contagem de pool constante, número de entradas na seguinte tabela de pool constante. Essa contagem é pelo menos um maior que o número real de entradas; veja a discussão a seguir. |
9 | |||
10 | cpsize (variável) | tabela | mesa de pool constante, uma matriz de entradas de pool constante de tamanho variável, contendo itens como números literais, strings e referências a classes ou métodos. Indexado a partir de 1, contendo ( contagem de pool constante - 1) número de entradas no total (consulte a nota). |
... | |||
... | |||
... | |||
10+ cpsize | 2 bytes | u2 | sinalizadores de acesso, uma máscara de bits |
11+ cpsize | |||
12+ cpsize | 2 bytes | u2 | identifica esta classe, indexe no pool constante para uma entrada do tipo "Classe" |
13+ cpsize | |||
14+ cpsize | 2 bytes | u2 | identifica a superclasse , indexa no pool constante para uma entrada do tipo "Classe" |
15+ cpsize | |||
16+ cpsize | 2 bytes | u2 | contagem de interface, número de entradas na seguinte tabela de interface |
17+ cpsize | |||
18+ cpsize | isize (variável) | tabela | tabela de interface: uma matriz de comprimento variável de índices de pool constantes que descrevem as interfaces implementadas por esta classe |
... | |||
... | |||
... | |||
18+ cpsize + iSize | 2 bytes | u2 | contagem de campos, número de entradas na tabela de campos a seguir |
19+ cpsize + iSize | |||
20+ cpsize + iSize | fsize (variável) | tabela | tabela de campos, matriz de campos de comprimento variável
cada elemento é uma estrutura field_info definida em https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.5 |
... | |||
... | |||
... | |||
20+ cpsize + iSize + fsize | 2 bytes | u2 | contagem de métodos, número de entradas na seguinte tabela de métodos |
21+ cpsize + iSize + fsize | |||
22+ cpsize + iSize + fsize | msize (variável) | tabela | tabela de métodos, matriz de métodos de comprimento variável
cada elemento é uma estrutura method_info definida em https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.6 |
... | |||
... | |||
... | |||
22+ cpsize + iSize + fsize + msize | 2 bytes | u2 | contagem de atributos, número de entradas na seguinte tabela de atributos |
23+ cpsize + iSize + fsize + msize | |||
24+ cpsize + iSize + fsize + msize | asize (variável) | tabela | tabela de atributos, matriz de atributos de comprimento variável
cada elemento é uma estrutura attribute_info definida em https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.7 |
... | |||
... | |||
... |
Representação em uma linguagem de programação semelhante a C
Como C não oferece suporte a vários arrays de comprimento variável dentro de uma estrutura, o código a seguir não compilará e servirá apenas como uma demonstração.
struct Class_File_Format {
u4 magic_number;
u2 minor_version;
u2 major_version;
u2 constant_pool_count;
cp_info constant_pool[constant_pool_count - 1];
u2 access_flags;
u2 this_class;
u2 super_class;
u2 interfaces_count;
u2 interfaces[interfaces_count];
u2 fields_count;
field_info fields[fields_count];
u2 methods_count;
method_info methods[methods_count];
u2 attributes_count;
attribute_info attributes[attributes_count];
}
A piscina constante
A mesa de pool constante é onde a maioria dos valores constantes literais são armazenados. Isso inclui valores como números de todos os tipos, strings, nomes de identificadores, referências a classes e métodos e descritores de tipo. Todos os índices, ou referências, a constantes específicas na tabela de pool de constantes são dados por números de 16 bits (tipo u2), onde o valor de índice 1 se refere à primeira constante na tabela (o valor de índice 0 é inválido).
Devido às escolhas históricas feitas durante o desenvolvimento do formato do arquivo, o número de constantes na tabela de pool constante não é realmente o mesmo que a contagem de pool constante que precede a tabela. Primeiro, a tabela é indexada começando em 1 (em vez de 0), mas a contagem deve ser interpretada como o índice máximo mais um. Além disso, dois tipos de constantes (longas e duplas) ocupam dois slots consecutivos na tabela, embora o segundo desses slots seja um índice fantasma que nunca é usado diretamente.
O tipo de cada item (constante) no pool de constantes é identificado por uma tag de byte inicial . O número de bytes após esta tag e sua interpretação dependem do valor da tag. Os tipos de constantes válidos e seus valores de tag são:
Byte de tag | Bytes adicionais | Descrição da constante | Versão introduzida |
---|---|---|---|
1 | 2+ x bytes (variável) |
Sequência UTF-8 (Unicode): uma sequência de caracteres prefixada por um número de 16 bits (tipo u2) indicando o número de bytes na sequência codificada que segue imediatamente (que pode ser diferente do número de caracteres). Observe que a codificação usada não é realmente UTF-8 , mas envolve uma ligeira modificação da forma de codificação padrão Unicode. | 1.0.2 |
3 | 4 bytes | Inteiro: um número de complemento de dois de 32 bits com sinal no formato big-endian | 1.0.2 |
4 | 4 bytes | Float: um número de ponto flutuante IEEE 754 de precisão única de 32 bits | 1.0.2 |
5 | 8 bytes | Longo: um número de complemento de dois de 64 bits com sinal no formato big-endian (ocupa dois slots na mesa de pool constante) | 1.0.2 |
6 | 8 bytes | Duplo: um número de ponto flutuante IEEE 754 de precisão dupla de 64 bits (leva dois slots na tabela de pool constante) | 1.0.2 |
7 | 2 bytes | Referência de classe: um índice dentro do pool constante para uma string UTF-8 contendo o nome de classe totalmente qualificado (em formato interno ) (big-endian) | 1.0.2 |
8 | 2 bytes | Referência de string: um índice dentro do pool constante para uma string UTF-8 (big-endian também) | 1.0.2 |
9 | 4 bytes | Referência de campo: dois índices dentro do pool constante, o primeiro apontando para uma referência de classe, o segundo para um descritor de nome e tipo. (big-endian) | 1.0.2 |
10 | 4 bytes | Referência de método: dois índices dentro do pool constante, o primeiro apontando para uma referência de classe, o segundo para um descritor de nome e tipo. (big-endian) | 1.0.2 |
11 | 4 bytes | Referência do método de interface: dois índices dentro do pool constante, o primeiro apontando para uma referência de classe, o segundo para um descritor de nome e tipo. (big-endian) | 1.0.2 |
12 | 4 bytes | Descritor de nome e tipo: dois índices para strings UTF-8 dentro do pool de constantes, o primeiro representando um nome (identificador) e o segundo um descritor de tipo especialmente codificado. | 1.0.2 |
15 | 3 bytes | Identificador de método: esta estrutura é usada para representar um identificador de método e consiste em um byte do descritor de tipo, seguido por um índice dentro do pool de constantes. | 7 |
16 | 2 bytes | Tipo de método: esta estrutura é usada para representar um tipo de método e consiste em um índice dentro do pool de constantes. | 7 |
17 | 4 bytes | Dinâmico: é usado para especificar uma constante calculada dinamicamente produzida pela invocação de um método de bootstrap. | 11 |
18 | 4 bytes | InvokeDynamic: é usado por uma instrução invokedynamic para especificar um método de bootstrap, o nome da invocação dinâmica, o argumento e os tipos de retorno da chamada e, opcionalmente, uma sequência de constantes adicionais chamadas de argumentos estáticos para o método de bootstrap. | 7 |
19 | 2 bytes | Módulo: é usado para identificar um módulo. | 9 |
20 | 2 bytes | Pacote: é usado para identificar um pacote exportado ou aberto por um módulo. | 9 |
Existem apenas dois tipos de constantes integrais, inteiros e longos. Outros tipos integrais que aparecem na linguagem de alto nível, como booleano, byte e short devem ser representados como uma constante inteira.
Nomes de classes em Java, quando totalmente qualificados, são tradicionalmente separados por pontos, como "java.lang.Object". No entanto, nas constantes de referência de classe de baixo nível, aparece um formulário interno que usa barras, como "java / lang / Object".
As strings Unicode, apesar do moniker "string UTF-8", não são realmente codificadas de acordo com o padrão Unicode, embora seja semelhante. Existem duas diferenças (consulte UTF-8 para uma discussão completa). A primeira é que o ponto de código U + 0000 é codificado como a sequência de dois bytes C0 80
(em hexadecimal) em vez da codificação de byte único padrão 00
. A segunda diferença é que os caracteres suplementares (aqueles fora do BMP em U + 10000 e acima) são codificados usando uma construção de par substituto semelhante ao UTF-16 em vez de serem codificados diretamente usando UTF-8. Nesse caso, cada um dos dois substitutos é codificado separadamente em UTF-8. Por exemplo, U + 1D11E é codificado como a sequência de 6 bytes ED A0 B4 ED B4 9E
, em vez da codificação UTF-8 correta de 4 bytes F0 9D 84 9E
.
Veja também
Referências
Leitura adicional
- Tim Lindholm , Frank Yellin (1999). The Java Virtual Machine Specification (segunda edição). Prentice Hall. ISBN 0-201-43294-3. Página visitada em 2008-10-13 .O documento oficial de definição da Java Virtual Machine , que inclui o formato do arquivo de classe. Tanto a primeira como a segunda edições do livro estão disponíveis gratuitamente online para visualização e / ou download .