Todos os amigos que estudam Java devem saber que Java usa a bandeira da independência de plataforma desde o início, dizendo "escreva uma vez, execute em qualquer lugar. Na verdade, quando se trata de irrelevância, a plataforma Java tem outra irrelevância, que é a independência da linguagem". ., para obter independência de linguagem, então a estrutura de arquivos da classe no sistema Java ou É muito importante dizer que é bytecode. Na verdade, Java teve dois conjuntos de especificações desde o início, um é a especificação da linguagem Java e o outro é a especificação da máquina virtual Java. A especificação da linguagem Java apenas estipula as restrições. relacionadas à linguagem Java e às regras, e as especificações da máquina virtual são realmente projetadas a partir de uma perspectiva de plataforma cruzada. Hoje daremos um exemplo prático para ver como deve ser o bytecode correspondente a um arquivo Class em Java. Este artigo primeiro explicará em geral em que consiste a classe de conteúdo e, em seguida, usará uma classe Java real para analisar a estrutura do arquivo da classe.
Antes de continuar, primeiro precisamos esclarecer os seguintes pontos:
1) Os arquivos de classe são compostos por fluxos de bytes baseados em 8 bytes. Esses fluxos de bytes são organizados estritamente na ordem especificada e não há intervalos entre os bytes. Para arquivos que excedem 8 bytes, os dados serão armazenados na ordem Big-Endian. isto é, o byte de ordem superior é armazenado no endereço inferior e o byte de ordem inferior é armazenado no endereço superior. Esta também é a chave para arquivos de classe multiplataforma, porque a arquitetura PowerPC usa ordem de armazenamento Big-Endian, enquanto os processadores da série x86 usam ordem de armazenamento Little-Endian, para que os arquivos de classe sejam mantidos em cada arquitetura de processador Armazenamento unificado Em ordem, as especificações da máquina virtual devem ser unificadas.
2) A estrutura do arquivo de classe usa uma estrutura semelhante à linguagem C para armazenar dados. Existem dois tipos principais de itens de dados: números não assinados e tabelas. Números não assinados são usados para expressar números, referências de índice e strings, como u1, u2. , u4 e u8 representam 1 byte, 2 bytes, 4 bytes e 8 bytes de números não assinados, respectivamente, e a tabela é uma estrutura composta composta por vários números não assinados e outras tabelas. Talvez todos aqui não tenham muita clareza sobre o que são números e tabelas sem sinal, mas não importa, explicarei com exemplos quando der os exemplos abaixo.
Depois de esclarecer os dois pontos acima, vamos dar uma olhada nos dados específicos contidos no fluxo de bytes organizados em ordem estrita no arquivo de classe:
Ao olhar para a imagem acima, há uma coisa que precisamos prestar atenção, como cp_info, cp_info representa o pool de constantes. Na imagem acima, constante_pool[constant_pool_count-1] é usado para representar o pool de constantes com constante_pool_co. constante unt-1, ela é expressa na forma de um array aqui, mas não pense erroneamente que os comprimentos constantes de todos os conjuntos de constantes são os mesmos. Na verdade, este lugar usa o método array apenas por conveniência de descrição, mas. não é assim. Nas linguagens de programação, um array do tipo int tem o mesmo comprimento de cada int. Depois de esclarecer esse ponto, vamos olhar para trás e ver o que cada item da imagem acima representa especificamente.
1) A magia u4 representa o número mágico, e o número mágico ocupa 4 bytes. Na verdade, significa que o tipo de arquivo é um arquivo Class, não uma imagem JPG ou filme AVI. O número mágico correspondente ao arquivo da Classe é 0xCAFEBABE.
2) u2 minor_version representa o número da versão secundária do arquivo Class, e este número de versão é uma representação de número não assinado do tipo u2.
3) u2 major_version representa o número da versão principal do arquivo de classe, e o número da versão principal é uma representação de número não assinado do tipo u2. major_version e minor_version são usados principalmente para indicar se a máquina virtual atual aceita a versão atual do arquivo de classe. As versões dos arquivos de classe compilados por diferentes versões de compiladores Java são diferentes. Uma versão superior da máquina virtual suporta a estrutura do arquivo Class compilada por uma versão inferior do compilador. Por exemplo, a máquina virtual correspondente ao Java SE 6.0 suporta a estrutura de arquivos Class compilada pelo compilador Java SE 5.0, mas não vice-versa.
4) u2 constante_pool_count representa o número de pools constantes. Aqui precisamos nos concentrar no que é o pool de constantes. Por favor, não o confunda com o pool de constantes de tempo de execução no modelo de memória Jvm. O pool de constantes no arquivo de classe armazena principalmente literais e referências de símbolos, onde os literais incluem principalmente strings. valor da constante final ou Ou o valor inicial de um determinado atributo, etc., enquanto as referências de símbolos armazenam principalmente os nomes totalmente qualificados de classes e interfaces, nomes de campos e descritores, nomes de métodos e descritores. Os nomes aqui podem ser fáceis de entender para todos, como para o. conceito de descritores, falaremos sobre isso mais tarde, quando discutirmos a tabela de campos e a tabela de métodos. Além disso, todos sabem que o modelo de memória do Jvm consiste em heap, pilha, área de método e contador de programa, e há uma área na área de método chamada pool de constantes de tempo de execução. imortalidade do compilador. Vários literais e referências de símbolos, mas o pool de constantes de tempo de execução é dinâmico. Ele pode adicionar outras constantes a ele em tempo de execução.
5) cp_info representa o conjunto constante, que contém os vários literais e referências de símbolos mencionados acima. Há um total de 14 itens de dados colocados no conjunto de constantes na Java Virtual Machine Specification Java SE 7 Edition. Cada constante é uma tabela e cada constante usa uma tag parcial comum para indicar de que tipo ela é.
Os detalhes específicos são brevemente descritos abaixo e iremos refiná-los em exemplos posteriores.
O sinalizador da tag CONSTANT_Utf8_info é 1, o sinalizador da tag CONSTANT_Integer_info da string codificada UTF-8 é 3, o sinalizador da tag CONSTANT_Float_info do literal inteiro é 4, o sinalizador da tag CONSTANT_Long_info do literal de ponto flutuante é 5, o sinalizador da tag CONSTANT_Double_info do literal inteiro longo O bit é 6, o sinalizador de tag CONSTANT_Class_info literal de precisão dupla é 7, A referência simbólica da tag CONSTANT_String_info da classe ou interface é 8, a tag literal CONSTANT_Fieldref_info do tipo string é 9, a referência simbólica da tag CONSTANT_Methodref_info do campo é 10, a referência simbólica do método na classe CONSTANT_InterfaceMethodref_info tag é 11, Simbólica referência ao método na tag CONSTANT_NameAndType_info da interface Sinalizador bit 12, nomes de campos e métodos e referências simbólicas a tipos
6) u2 access_flags representa as informações de acesso da classe ou interface, conforme mostrado na figura a seguir:
7) u2 this_class representa o índice do pool constante da classe, apontando para a constante de CONSTANT_Class_info no pool constante
8) u2 super_class representa o índice da superclasse, apontando para a constante de CONSTANT_Class_info no pool de constantes
9) u2 interface_counts representa o número de interfaces
10) u2 interface[interface_counts] representa a tabela de interface, cada item nela aponta para a constante CONSTANT_Class_info no pool de constantes
11) u2 field_count representa o número de variáveis de instância e variáveis de classe da classe
12) field_info campos[fields_count] representa as informações da tabela de campos, onde a estrutura da tabela de campos é mostrada abaixo:
Na figura acima, access_flags representa a representação de acesso do campo. Por exemplo, o campo é público, privado e protegido. etc., name_index representa o nome do campo, apontando para a constante do tipo CONSTANT_UTF8_info no pool de constantes, descriptor_index representa o descritor do campo, que também aponta para a constante do tipo CONSTANT_UTF8_info no pool de constantes, atributos_count representa o número de tabelas de atributos na tabela de campos e na tabela de atributos É uma estrutura extensível usada para descrever campos, métodos e atributos de classe. Diferentes versões da máquina virtual Java suportam diferentes números de tabelas de atributos.
13) u2 methods_count representa o número de tabelas de métodos
14) method_info representa a tabela de métodos. A estrutura específica da tabela de métodos é mostrada na figura abaixo:
Entre eles, access_flags representa a representação de acesso do método, name_index representa o índice do nome, descriptor_index representa o descritor do método, atributos_count e atributos_info são semelhantes às tabelas de atributos na tabela de campos, exceto que os atributos na tabela de atributos na tabela de campos e na tabela de métodos são diferentes, como O atributo Code na tabela de métodos representa o código do método, mas não há nenhum atributo Code na tabela de campos. Quantos atributos existem na classe específica serão discutidos posteriormente, quando examinarmos a tabela de atributos na estrutura do arquivo de classe.
15) attribute_count representa o número de tabelas de atributos. Quando se trata de tabelas de atributos, precisamos esclarecer os seguintes pontos:
A tabela de atributos existe no final da estrutura do arquivo de classe, na tabela de campos, tabela de métodos e atributo de código. Ou seja, a tabela de atributos também pode existir na tabela de atributos. Atributos diferentes têm comprimentos diferentes.
Após descrever a composição de cada item da estrutura do arquivo de Classe acima, utilizamos um exemplo prático para explicar o conteúdo a seguir.
Copie o código do código da seguinte forma:
pacote com.ejushang.TestClass;
classe pública TestClass implementa Super{
private static final int staticVar = 0;
private int instanceVar=0;
public int instanceMethod(int param){
retornar parâmetro+1;
}
}
interfaceSuper{ }
A estrutura binária de TestClass.class correspondente a TestClass.java compilada por meio de javac de jdk1.6.0_37 é mostrada na figura abaixo:
A seguir, analisaremos o fluxo de bytes na figura acima com base na estrutura de arquivos da classe mencionada anteriormente.
1) Número mágico <br/> Pela estrutura do arquivo da Classe, sabemos que os primeiros 4 bytes são o número mágico. Na imagem acima, o conteúdo do endereço 00000000h-00000003h é o número mágico. podemos saber o número mágico do arquivo de classe. O número é 0xCAFEBABE.
2) Números de versão principal e secundária <br/>Os próximos 4 bytes são os números de versão principal e secundária. Na figura acima, podemos ver que os números correspondentes de 00000004h-00000005h são 0×0000, portanto, a versão menor da classe. é 0×0000, e o conteúdo correspondente de 00000006h-00000007h é 0×0032, então a versão major_version do arquivo de classe é 0×0032, que é exatamente a versão principal e secundária correspondente à classe compilada por jdk1.6.0 sem o parâmetro de destino.
3) O número do pool constante <br/> Os próximos 2 bytes representam o número do pool constante de 00000008h-00000009h A partir da figura acima, podemos saber que seu valor é 0×0018, que é 24 em decimal, mas para. O número de conjuntos constantes precisa ser esclarecido. O número de conjuntos constantes é constante_pool_count-1. A razão pela qual é reduzido em um é porque o índice 0 significa que os itens de dados na classe não fazem referência a nenhuma constante no conjunto constante.
4) Conjunto de constantes <br/> Dissemos acima que existem diferentes tipos de constantes no conjunto de constantes. Vamos dar uma olhada na primeira constante de TestClass.class. Sabemos que cada constante é representada por um identificador de tag do tipo u1. O tipo de constante, em 0000000ah na imagem acima O conteúdo é 0x0A, que convertido para o sistema secundário é 10. Pela descrição acima do tipo constante, pode-se observar que a constante com tag 10 é Constant_Methodref_info, e a estrutura de Constant_Methodref_info é conforme mostrado na figura abaixo:
Entre eles, class_index aponta para a constante do tipo CONSTANT_Class_info no pool de constantes. Pode-se observar na estrutura do arquivo binário de TestClass que o valor de class_index é 0×0004 (o endereço é 0000000bh-0000000ch), o que significa que aponta para. a quarta constante.
name_and_type_index aponta para a constante do tipo CONSTANT_NameAndType_info no conjunto de constantes. Como pode ser visto na figura acima, o valor de name_and_type_index é 0×0013, o que significa que aponta para a 19ª constante no conjunto de constantes.
A seguir, você pode usar o mesmo método para encontrar todas as constantes no conjunto de constantes. No entanto, o JDK fornece uma ferramenta conveniente que nos permite visualizar as constantes contidas no conjunto de constantes. Você pode obter todas as constantes no pool de constantes por meio de javap -verbose TestClass.
Na imagem acima, podemos ver claramente que existem 24 constantes no conjunto de constantes em TestClass. Não se esqueça da 0ª constante, porque a 0ª constante é usada para indicar que os itens de dados na Classe não fazem referência a nenhuma constante na. piscina constante. A partir da análise acima, sabemos que o primeiro método de representação constante de TestClass é que a quarta constante apontada por class_index é java/lang/Object, e o 19º valor constante apontado por name_and_type_index é <init>:()V. veja aqui que a primeira constante que representa um método representa o método construtor de instância gerado pelo compilador java. Outras constantes no conjunto de constantes podem ser analisadas da mesma maneira. OK, depois de analisar o pool de constantes, vamos analisar access_flags a seguir.
5) u2 access_flags representa informações de acesso sobre classes ou interfaces. Por exemplo, Class representa se é uma classe ou uma interface, se é pública, estática, final, etc. O significado do sinalizador de acesso específico foi mencionado anteriormente. Vamos dar uma olhada no sinalizador de acesso de TestClass. O sinalizador de acesso da Classe é de 0000010dh-0000010e, e o valor é 0×0021. De acordo com os bits do sinalizador de vários sinalizadores de acesso mencionados anteriormente, podemos saber: 0×0021=0×0001|0×0020, ou seja, ACC_PUBLIC e ACC_SUPER são True, ACC_PUBLIC é fácil de entender e ACC_SUPER é um sinalizador que será carregado por classes compiladas após jdk1.2.
6) u2 this_class representa o valor do índice da classe, que é usado para representar o nome totalmente qualificado da classe. O valor do índice da classe é mostrado na figura abaixo:
Como pode ser visto claramente na figura acima, o valor do índice da classe é 0×0003, que corresponde à terceira constante do pool de constantes. Através do resultado javap, sabemos que a terceira constante é uma constante do tipo CONSTANT_Class_info, através do resultado do javap. onde podemos saber todos os detalhes da classe. O nome qualificado é: com/ejushang/TestClass /TestClass.
7) u2 super_class representa o valor do índice da classe pai da classe atual. O valor do índice aponta para uma constante do tipo CONSTANT_Class_info no conjunto de constantes. 0×0004 Verifique as primeiras quatro constantes do pool de constantes, pode-se observar que o nome totalmente qualificado da classe pai de TestClass é: java/lang/Object.
8) interfaces_count e interfaces[interfaces_count] representam o número de interfaces e cada interface específica. O número de interfaces e interfaces de TestClass são mostrados na figura abaixo, onde 0×0001 significa que o número de interfaces é 1 e 0×. 0005 significa o índice da interface no valor do pool constante, encontre a quinta constante no pool constante, seu tipo é CONSTANT_Class_info e seu valor é: com/ejushang/TestClass/Super
9) field_count e field_info , field_count representa o número de tabelas field_info na classe e field_info representa as variáveis de instância e variáveis de classe da classe. Deve-se observar aqui que field_info não inclui campos herdados da classe pai. field_info é como mostrado na figura abaixo:
Dentre eles, access_flags representa a flag de acesso do campo, como público, privado, protegido, estático, final, etc. O valor de access_flags é conforme mostrado na figura abaixo:
Entre eles, name_index e descriptor_index são ambos valores de índice do pool constante, que representam respectivamente o nome do campo e o descritor do campo. O nome do campo é fácil de entender, mas como entender o descritor do campo. campo? Na verdade, na especificação JVM, os descritores de campo são especificados conforme mostrado na figura a seguir:
Dentre eles, todos precisam prestar atenção na última linha da imagem acima. Ela representa o descritor de um array unidimensional. O descritor para String[][] será [[Ljava/lang/String, e a descrição para String[][] será [[Ljava/lang/String. int[][] O símbolo é [[I. Os seguintes atributos_count e atributos_info representam o número de tabelas de atributos e tabelas de atributos, respectivamente. Vamos pegar o TestClass acima como exemplo e dar uma olhada na tabela de campos do TestClass.
Primeiro, vamos dar uma olhada no número de campos. O número de campos em TestClass é mostrado na figura abaixo:
Como pode ser visto na imagem acima, TestClass possui dois campos. Olhando o código-fonte do TestClass, podemos ver que de fato existem apenas dois campos. private int staticVar, que A representação binária no arquivo de classe é mostrada abaixo:
Entre eles, 0x001A representa o sinalizador de acesso. Observando a tabela access_flags, podemos saber que é ACC_PRIVATE, ACC_STATIC, ACC_FINAL. Em seguida, 0×0006 e 0×0007 representam a 6ª e 7ª constantes no pool de constantes, respectivamente. olhando para o pool de constantes, podemos saber que seus valores são: staticVar e I, onde staticVar é o nome do campo e I é o descritor do campo. Através da explicação dos descritores acima, o que descrevo é uma variável do tipo int. A seguir, 0×0001 representa o número de tabelas de atributos na tabela de campos staticVar. Na figura acima, pode-se observar que há 1 tabela de atributos correspondente. para o campo staticVar 0×0008 representa a 8ª constante no conjunto de constantes. Olhando para o conjunto de constantes, você pode ver que este atributo é o atributo ConstantValue, e o formato do atributo ConstantValue é mostrado na figura abaixo:
Entre eles, attribute_name_index expressa o índice do pool constante do nome do atributo. Neste exemplo, é ConstantValue. Neste exemplo, é 0. ×0009 Você pode visualizar a 9ª constante. Você sabe, ela representa uma constante do tipo CONSTANT_Integer_info cujo valor é 0.
Dito isto private static final int staticVar=0, vamos falar sobre private int instanceVar=0 de TestClass. Neste exemplo, a representação binária de instanceVar é mostrada na figura abaixo:
Entre eles, 0×0002 significa que a marca de acesso é ACC_PRIVATE, 0x000A significa o nome do campo, que aponta para a 10ª constante no pool de constantes, você pode saber que o nome do campo é instanceVar e. 0× 0007 representa o descritor do campo, que aponta para a 7ª constante no pool de constantes. Olhando para o pool de constantes, você pode saber que a 7ª constante é I, que representa o tipo de instanceVar. número de tabelas de atributos é 0. .
10) Methods_count e Methods_info , onde Methods_count representa o número de métodos e Methods_info representa a tabela de métodos, onde a estrutura da tabela de métodos é mostrada na figura abaixo:
Como pode ser visto na figura acima, as estruturas de method_info e field_info são muito semelhantes. Todos os bits de flag e valores de access_flag na tabela de métodos são mostrados na figura abaixo:
Entre eles, name_index e descriptor_index representam o nome e o descritor do método, e são índices que apontam para o pool de constantes respectivamente. Aqui precisamos explicar o descritor do método. A estrutura do descritor do método é: (lista de parâmetros) valor de retorno. Por exemplo, o descritor de public int instanceMethod (int param) é: (I) I, o que significa que tem um int. parâmetro de tipo. E o valor de retorno também é um método do tipo int. O próximo é o número de atributos e a tabela de atributos. Embora a tabela de métodos e a tabela de campos tenham o número de atributos e a tabela de atributos, os atributos que eles contêm são. diferente. A seguir, vamos dar uma olhada na representação binária da tabela de métodos usando TestClass. Primeiro, vamos dar uma olhada no número de tabelas de métodos. A captura de tela é a seguinte:
Como pode ser visto na figura acima, o número de tabelas de métodos é 0×0002, o que significa que existem dois métodos. A seguir, vamos analisar o primeiro método. Vejamos primeiro o access_flag, name_index, descriptor_index do primeiro método de TestClass. . A captura de tela é a seguinte:
Pela figura acima, podemos saber que access_flags é 0×0001. Pela descrição acima do sinalizador access_flags, podemos ver que o valor de access_flags do método é ACC_PUBLIC e o name_index é 0x000B. A 11ª constante, sabendo que o nome do método é <init>, 0x000C significa descriptor_index significa a 12ª constante no conjunto de constantes, e seu valor é ()V, o que significa que o método <init> não possui parâmetros e valor de retorno. Na verdade, este é o compilador de métodos construtores de instância gerados automaticamente. O próximo 0×0001 indica que a tabela de métodos do método <init> possui 1 atributo. A captura de tela do atributo é a seguinte:
Como pode ser visto na figura acima, a constante no pool de constantes correspondente a 0x000D é Code, que representa o atributo Code do método. Portanto, aqui todos devem entender que os códigos do método são armazenados no atributo Code no atributo. table na tabela de métodos do arquivo Class. A seguir analisamos o atributo Code. A estrutura do atributo Code é mostrada na figura abaixo:
Entre eles, atributo_nome_index aponta para a constante cujo valor é Código no conjunto de constantes, e o comprimento de atributo_comprimento indica o comprimento da tabela de atributos de código (deve-se notar que o comprimento não inclui o comprimento de 6 bytes de atributo_nome_index e atributo_comprimento ).
max_stack representa a profundidade máxima da pilha. A máquina virtual aloca a profundidade dos operandos no quadro da pilha com base neste valor em tempo de execução e max_locals representa o espaço de armazenamento da tabela de variáveis locais.
A unidade de max_locals é slot, que é a menor unidade para a máquina virtual alocar memória para variáveis locais. Em tempo de execução, os tipos de dados que não excedem os tipos de 32 bits, como byte, char, int, etc., ocupam 1. slot, enquanto duplo e longo Um tipo de dados de 64 bits precisa alocar 2 slots. Além disso, o valor de max_locals não é a soma da memória exigida por todas as variáveis locais, porque os slots podem ser reutilizados quando a variável local excede seu escopo. o slot ocupado será reutilizado.
code_length representa o número de instruções de bytecode e code representa instruções de bytecode. A partir da figura acima, podemos saber que o tipo de código é u1. O valor de um tipo u1 é 0×00-0xFF e o decimal correspondente é 0-. 255. Atualmente, a especificação da máquina virtual definiu mais de 200 instruções.
exceção_tabela_comprimento e exceção_tabela representam respectivamente as informações de exceção correspondentes ao método.
Atributos_count e atributo_info representam o número de atributos e a tabela de atributos no atributo Código, respectivamente. Pode-se ver aqui que a tabela de atributos é muito flexível na estrutura de arquivos da Classe. Ela pode existir no arquivo de Classe, tabela de métodos, campo. tabela e atributo de código.
A seguir, continuamos a analisar o exemplo acima. A partir da captura de tela do atributo Code do método init acima, podemos ver que o comprimento da tabela de atributos é 0×00000026, o valor de max_stack é 0×0002 e o valor. de max_locals é 0× 0001, o comprimento de code_length é 0x0000000A, então 00000149h- 00000152h é bytecode. Em seguida, o comprimento de exceção_table_length é 0x0000 e o valor de attribute_count é 0x0001. O valor de 00000157h-00000158h é 0x000E, que representa o nome do atributo no pool de constantes. para obter o 14º O valor da constante é LineNumberTable, LineNu. mberTable é usado para descrever a correspondência entre o número da linha do código-fonte Java e o número da linha do bytecode. Não é um atributo obrigatório em tempo de execução. Se você cancelar a geração dessas informações por meio do parâmetro do compilador -g:none, o maior impacto será. be Quando ocorre uma exceção, o número da linha de erro não pode ser exibido na pilha e os pontos de interrupção não podem ser definidos de acordo com o código-fonte durante a depuração. A seguir, vamos dar uma olhada na estrutura de LineNumberTable, conforme mostrado abaixo:
Entre eles, o atributo_name_index foi mencionado acima e representa o índice do conjunto constante, o atributo_length representa o comprimento do atributo e as tabelas start_pc e line_number representam o número da linha do bytecode e o número da linha do código-fonte. O fluxo de bytes da propriedade LineNumberTable neste exemplo é mostrado abaixo:
Depois de analisar o primeiro método do TestClass acima, podemos analisar o segundo método do TestClass da mesma maneira.
Entre eles, access_flags é 0×0001, name_index é 0x000F e descriptor_index é 0×0010. Observando o pool de constantes, você pode saber que este método é o método public int instanceMethod (int param). Através de um método semelhante ao acima, podemos saber que o atributo Code de instanceMethod é conforme mostrado na figura abaixo:
Por fim, vamos analisar os atributos do arquivo Class. De 00000191h a 00000199h está a tabela de atributos no arquivo Class, onde 0×0011 representa o nome do atributo. Olhando para o pool de constantes, podemos saber que o nome do atributo é SourceFile. Vamos dar uma olhada na estrutura do SourceFile conforme mostrado na figura:
Entre eles, attribute_length é o comprimento do atributo e sourcefile_index aponta para a constante no conjunto de constantes cujo valor é o nome do arquivo de código-fonte. Neste exemplo, a captura de tela do atributo SourceFile é a seguinte:
Entre eles, attribute_length é 0×00000002, o que significa que o comprimento é de 2 bytes e o valor de sourcefile_index é 0×0012. Olhando para a 18ª constante no pool de constantes, você pode saber que o nome do arquivo de código-fonte é TestClass. .Java
Por fim, espero que amigos interessados em tecnologia possam se comunicar mais. Weibo pessoal: (http://weibo.com/xmuzyq)