Freunde, die Java studieren, sollten alle wissen, dass Java von Anfang an das Banner der Plattformunabhängigkeit verwendet hat und sagt: „Einmal schreiben, überall ausführen“. Tatsächlich hat die Java-Plattform eine weitere Irrelevanz, nämlich die Sprachunabhängigkeit , um Sprachunabhängigkeit zu erreichen, dann die Dateistruktur der Klasse im Java-System oder Es ist sehr wichtig zu sagen, dass es sich um Bytecode handelt. Tatsächlich gab es in Java von Anfang an zwei Sätze von Spezifikationen, einen ist die Java-Sprachspezifikation und der andere ist die Java-Sprachspezifikation, die nur die Einschränkungen festlegt in Bezug auf die Java-Sprache und -Regeln sowie die Spezifikationen für virtuelle Maschinen sind tatsächlich aus einer plattformübergreifenden Perspektive konzipiert. Heute werden wir anhand eines praktischen Beispiels sehen, wie der Bytecode einer Klassendatei in Java aussehen sollte. In diesem Artikel wird zunächst allgemein erläutert, aus welchem Inhalt eine Klasse besteht, und dann wird eine tatsächliche Java-Klasse verwendet, um die Dateistruktur der Klasse zu analysieren.
Bevor wir fortfahren, müssen wir zunächst folgende Punkte klären:
1) Klassendateien bestehen aus 8-Byte-basierten Byteströmen. Diese Byteströme sind streng in der angegebenen Reihenfolge angeordnet und es gibt keine Lücken zwischen den Bytes. Bei Dateien mit mehr als 8 Byte werden die Daten in der Big-Endian-Reihenfolge gespeichert. Das heißt, das höherwertige Byte wird an der niedrigen Adresse gespeichert, und das niederwertige Byte wird tatsächlich an der hohen Adresse gespeichert. Dies ist auch der Schlüssel zu plattformübergreifenden Klassendateien, da die PowerPC-Architektur die Big-Endian-Speicherreihenfolge verwendet, während die Prozessoren der x86-Serie die Little-Endian-Speicherreihenfolge verwenden, sodass Klassendateien unter jeder Prozessorarchitektur verwaltet werden können Einheitlicher Speicher In dieser Reihenfolge müssen die Spezifikationen der virtuellen Maschine vereinheitlicht werden.
2) Die Klassendateistruktur verwendet eine C-Sprachstruktur zum Speichern von Daten. Es gibt zwei Haupttypen von Datenelementen: vorzeichenlose Zahlen und vorzeichenlose Zahlen, die zum Ausdrücken von Zahlen, Indexreferenzen und Zeichenfolgen verwendet werden , u4 und u8 repräsentieren 1 Byte, 2 Byte, 4 Byte bzw. 8 Byte vorzeichenlose Zahlen, und die Tabelle ist eine zusammengesetzte Struktur, die aus mehreren vorzeichenlosen Zahlen und anderen Tabellen besteht. Vielleicht ist sich hier nicht jeder darüber im Klaren, was vorzeichenlose Zahlen und Tabellen sind, aber das spielt keine Rolle, ich werde es anhand von Beispielen erklären, wenn ich die folgenden Beispiele gebe.
Nachdem wir die beiden oben genannten Punkte geklärt haben, werfen wir einen Blick auf die spezifischen Daten, die im Byte-Stream enthalten sind und in der Klassendatei in strenger Reihenfolge angeordnet sind:
Wenn wir uns das Bild oben ansehen, müssen wir auf eines achten, z. B. cp_info, cp_info stellt den Konstantenpool dar. Im Bild oben wird Constant_pool [constant_pool_count-1] verwendet, um den Konstantenpool mit Constant_pool_co darzustellen unt-1-Konstante wird hier in Form eines Arrays ausgedrückt, aber denken Sie nicht fälschlicherweise, dass die konstanten Längen aller Konstantenpools gleich sind. Tatsächlich wird an dieser Stelle die Array-Methode nur zur Vereinfachung der Beschreibung verwendet, aber In Programmiersprachen ist dies nicht der Fall. Ein Array vom Typ int hat die gleiche Länge wie jedes int. Nachdem wir diesen Punkt geklärt haben, blicken wir zurück und sehen, was jedes Element im obigen Bild konkret darstellt.
1) u4 magic stellt die magische Zahl dar und die magische Zahl belegt 4 Bytes. Was macht die magische Zahl? Es bedeutet tatsächlich, dass es sich bei dem Dateityp um eine Klassendatei und nicht um ein JPG-Bild oder einen AVI-Film handelt. Die magische Zahl, die der Klassendatei entspricht, ist 0xCAFEBABE.
2) u2 Minor_Version stellt die Nebenversionsnummer der Klassendatei dar, und diese Versionsnummer ist eine vorzeichenlose Zahlendarstellung des Typs u2.
3) u2-Hauptversion stellt die Hauptversionsnummer der Klassendatei dar, und die Hauptversionsnummer ist eine vorzeichenlose Zahlendarstellung des Typs u2. Hauptversion und Nebenversion werden hauptsächlich verwendet, um anzuzeigen, ob die aktuelle virtuelle Maschine die aktuelle Version der Klassendatei akzeptiert. Die Versionen von Klassendateien, die von verschiedenen Versionen von Java-Compilern kompiliert werden, sind unterschiedlich. Eine höhere Version der virtuellen Maschine unterstützt die Klassendateistruktur, die von einer niedrigeren Version des Compilers kompiliert wurde. Beispielsweise unterstützt die virtuelle Maschine, die Java SE 6.0 entspricht, die vom Java SE 5.0-Compiler kompilierte Klassendateistruktur, umgekehrt jedoch nicht.
4) u2 konstanter_pool_count repräsentiert die Anzahl der konstanten Pools. Hier müssen wir uns auf den Konstantenpool konzentrieren. Bitte verwechseln Sie ihn nicht mit dem Laufzeitkonstantenpool im JVM-Speichermodell. Der Konstantenpool in der Klassendatei speichert hauptsächlich Literale und Symbolreferenzen Wert der Endkonstante oder Oder der Anfangswert eines bestimmten Attributs usw., während Symbolreferenzen hauptsächlich die vollständig qualifizierten Namen von Klassen und Schnittstellen, Feldnamen und Deskriptoren, Methodennamen und Deskriptoren speichern. Die Namen sind hier möglicherweise für jeden leicht verständlich Das Konzept der Deskriptoren wird später besprochen, wenn wir die Feldtabelle und die Methodentabelle besprechen. Darüber hinaus weiß jeder, dass das Speichermodell von JVM aus Heap, Stapel, Methodenbereich und Programmzähler besteht und dass es im Methodenbereich einen Bereich gibt, der als Laufzeitkonstantenpool bezeichnet wird Unsterblichkeit des Compilers, aber der Laufzeitkonstantenpool ist dynamisch. Er kann zur Laufzeit andere Konstanten hinzufügen.
5) cp_info stellt den Konstantenpool dar, der die verschiedenen oben genannten Literale und Symbolreferenzen enthält. Im Konstantenpool der Java Virtual Machine Specification Java SE 7 Edition sind insgesamt 14 Datenelemente enthalten. Jede Konstante ist eine Tabelle und jede Konstante verwendet ein gemeinsames Teil-Tag, um anzugeben, um welchen Typ es sich handelt.
Die spezifischen Details werden im Folgenden kurz beschrieben und wir werden sie in späteren Beispielen verfeinern.
Das CONSTANT_Utf8_info-Tag-Flag ist 1, die UTF-8-codierte Zeichenfolge CONSTANT_Integer_info-Tag-Flag ist 3, das ganzzahlige Literal CONSTANT_Float_info-Tag-Flag ist 4, das Gleitkomma-Literal CONSTANT_Long_info-Tag-Flag ist 5, das lange ganzzahlige Literal CONSTANT_Double_info-Tag-Flag Das Bit ist 6, Das CONSTANT_Class_info-Tag-Flag für das Literal mit doppelter Genauigkeit ist 7. Die symbolische Referenz des CONSTANT_String_info-Tags der Klasse oder Schnittstelle ist 8, das literale CONSTANT_Fieldref_info-Tag des String-Typs ist 9, die symbolische Referenz des Feld-CONSTANT_Methodref_info-Tags ist 10, die symbolische Referenz der Methode in der Klasse CONSTANT_InterfaceMethodref_info-Tag ist 11, Symbolisch Verweis auf die Methode im Interface-Tag CONSTANT_NameAndType_info Flag-Bit 12, Namen von Feldern und Methoden sowie symbolische Verweise auf Typen
6) u2 access_flags stellt die Zugriffsinformationen der Klasse oder Schnittstelle dar, wie in der folgenden Abbildung dargestellt:
7) u2 this_class stellt den Konstantenpoolindex der Klasse dar und zeigt auf die Konstante von CONSTANT_Class_info im Konstantenpool
8) u2 super_class stellt den Index der Superklasse dar und zeigt auf die Konstante CONSTANT_Class_info im Konstantenpool
9) u2 interface_counts repräsentiert die Anzahl der Schnittstellen
10) u2 interface[interface_counts] stellt die Schnittstellentabelle dar, jedes Element darin verweist auf die Konstante CONSTANT_Class_info im Konstantenpool
11) u2 Fields_Count repräsentiert die Anzahl der Instanzvariablen und Klassenvariablen der Klasse
12) field_info Felder [fields_count] stellt die Informationen der Feldtabelle dar, wobei die Struktur der Feldtabelle wie folgt ist:
In der obigen Abbildung stellt access_flags die Zugriffsdarstellung des Feldes dar. Das Feld ist beispielsweise öffentlich, privat und geschützt. usw., name_index stellt den Feldnamen dar und zeigt auf die Konstante vom Typ CONSTANT_UTF8_info im Konstantenpool, descriptor_index stellt den Deskriptor des Feldes dar, der auch auf die Konstante vom Typ CONSTANT_UTF8_info im Konstantenpool zeigt, attributes_count stellt die Anzahl der Attributtabellen dar in der Feldtabelle und der Attributtabelle Es handelt sich um eine erweiterbare Struktur zur Beschreibung von Feldern, Methoden und Klassenattributen. Verschiedene Versionen der Java Virtual Machine unterstützen eine unterschiedliche Anzahl von Attributtabellen.
13) u2 method_count repräsentiert die Anzahl der Methodentabellen
14) method_info stellt die Methodentabelle dar. Die spezifische Struktur der Methodentabelle ist in der folgenden Abbildung dargestellt:
Unter diesen stellt access_flags die Zugriffsdarstellung der Methode dar, name_index stellt den Index des Namens dar, descriptor_index stellt den Deskriptor der Methode dar, attributes_count und attribute_info ähneln den Attributtabellen in der Feldtabelle, mit der Ausnahme, dass die Attribute in der Attributtabelle sind Die Feldtabelle und die Methodentabelle sind unterschiedlich, z. B. Das Code-Attribut in der Methodentabelle stellt den Code der Methode dar, aber es gibt kein Code-Attribut in der Feldtabelle. Wie viele Attribute es in der jeweiligen Klasse gibt, wird später erläutert, wenn wir uns die Attributtabelle in der Klassendateistruktur ansehen.
15) attribute_count stellt die Anzahl der Attributtabellen dar. Wenn es um Attributtabellen geht, müssen wir die folgenden Punkte klären:
Die Attributtabelle befindet sich am Ende der Klassendateistruktur, in der Feldtabelle, der Methodentabelle und dem Codeattribut. Das heißt, die Attributtabelle kann auch in der Attributtabelle vorhanden sein. Verschiedene Attribute haben unterschiedliche Längen
Nachdem wir oben die Zusammensetzung jedes Elements in der Klassendateistruktur beschrieben haben, erläutern wir anhand eines praktischen Beispiels den folgenden Inhalt.
Kopieren Sie den Codecode wie folgt:
Paket com.ejushang.TestClass;
Die öffentliche Klasse TestClass implementiert Super{
private static final int staticVar = 0;
private int InstanzVar=0;
public int exampleMethod(int param){
return param+1;
}
}
Schnittstelle Super{ }
Die Binärstruktur von TestClass.class, die TestClass.java entspricht und mit javac von jdk1.6.0_37 kompiliert wurde, ist in der folgenden Abbildung dargestellt:
Als Nächstes analysieren wir den Bytestream in der obigen Abbildung basierend auf der zuvor erwähnten Dateistruktur der Klasse.
1) Magische Zahl <br/>Aus der Dateistruktur der Klasse wissen wir, dass die ersten 4 Bytes die magische Zahl sind. Im Bild oben ist der Inhalt der Adresse 00000000h-00000003h die magische Zahl. Wir können die magische Nummer der Klassendatei kennen. Die Nummer ist 0xCAFEBABE.
2) Haupt- und Nebenversionsnummern <br/>Die nächsten 4 Bytes sind die Haupt- und Nebenversionsnummern. Aus der obigen Abbildung können wir ersehen, dass die entsprechenden Zahlen von 00000004h-00000005h 0×0000 sind, also die Nebenversion der Klasse ist 0×0000, und der entsprechende Inhalt von 00000006h-00000007h ist 0×0032, daher ist die Hauptversion der Klassendatei 0×0032, was genau die Haupt- und Nebenversion ist, die der von jdk1.6.0 kompilierten Klasse ohne entspricht Zielparameter.
3) Die Anzahl der Konstantenpools <br/>Die nächsten 2 Bytes stellen die Anzahl der Konstantenpools von 00000008h-00000009h dar. Aus der obigen Abbildung können wir erkennen, dass der Wert 0×0018 ist, was 24 in Dezimalzahl ist Die Anzahl der Konstantenpools muss geklärt werden. Der Grund, warum sie um eins reduziert wird, liegt darin, dass der Index 0 bedeutet, dass die Datenelemente in der Klasse keine Konstanten im Konstantenpool referenzieren.
4) Konstantenpool <br/>Wir haben oben gesagt, dass es verschiedene Arten von Konstanten im Konstantenpool gibt. Schauen wir uns die erste Konstante von TestClass.class an. Wir wissen, dass jede Konstante durch einen Tag-Bezeichner vom Typ u1 dargestellt wird. Der Konstantentyp bei 0000000 Ah im obigen Bild Der Inhalt ist 0x0A, der in das sekundäre System konvertiert wird, ist 10. Aus der obigen Beschreibung des Konstantentyps ist ersichtlich, dass die Konstante mit Tag 10 Constant_Methodref_info ist und die Struktur von Constant_Methodref_info wie in der folgenden Abbildung dargestellt ist:
Unter diesen zeigt class_index auf die Konstante vom Typ CONSTANT_Class_info im Konstantenpool. Aus der Binärdateistruktur von TestClass ist ersichtlich, dass der Wert von class_index 0 × 0004 ist (die Adresse ist 0000000bh-0000000ch), was bedeutet, dass er auf zeigt die vierte Konstante.
name_and_type_index zeigt auf die Konstante vom Typ CONSTANT_NameAndType_info im Konstantenpool. Wie aus der obigen Abbildung ersichtlich ist, beträgt der Wert von name_and_type_index 0 × 0013, was bedeutet, dass er auf die 19. Konstante im Konstantenpool zeigt.
Als Nächstes können Sie mit derselben Methode alle Konstanten im Konstantenpool finden. JDK bietet jedoch ein praktisches Tool, mit dem wir die im Konstantenpool enthaltenen Konstanten anzeigen können. Sie können alle Konstanten im Konstantenpool über javap -verbose TestClass abrufen. Der Screenshot sieht wie folgt aus:
Aus dem Bild oben können wir deutlich erkennen, dass der Konstantenpool in TestClass 24 Konstanten enthält. Vergessen Sie nicht die 0. Konstante, da die 0. Konstante verwendet wird, um anzuzeigen, dass die Datenelemente in der Klasse auf keine Konstanten in der Klasse verweisen konstanter Pool. Aus der obigen Analyse wissen wir, dass die erste konstante Darstellungsmethode von TestClass darin besteht, dass die vierte Konstante, auf die class_index zeigt, java/lang/Object ist und der 19. konstante Wert, auf den name_and_type_index zeigt, <init>:()V ist Hier ist zu sehen, dass die erste Konstante, die eine Methode darstellt, die vom Java-Compiler generierte Instanzkonstruktormethode darstellt. Andere Konstanten im Konstantenpool können auf die gleiche Weise analysiert werden. OK, nachdem wir den Konstantenpool analysiert haben, analysieren wir als nächstes access_flags.
5) u2 access_flags stellt Zugriffsinformationen zu Klassen oder Schnittstellen dar. Klasse stellt beispielsweise dar, ob es sich um eine Klasse oder eine Schnittstelle handelt, ob sie öffentlich, statisch, endgültig usw. ist. Die Bedeutung des spezifischen Zugriffsflags wurde bereits erwähnt. Werfen wir einen Blick auf das Zugriffsflag von TestClass. Das Zugriffsflag der Klasse reicht von 0000010dh bis 0000010e, und der Wert ist 0×0021. Gemäß den zuvor erwähnten Flagbits verschiedener Zugriffsflags können wir Folgendes wissen: 0×0021=0×0001|0×0020, d. h. ACC_PUBLIC und ACC_SUPER sind wahr, ACC_PUBLIC ist leicht zu verstehen und ACC_SUPER ist ein Flag, das von Klassen getragen wird, die nach jdk1.2 kompiliert werden.
6) u2 this_class stellt den Indexwert der Klasse dar, der zur Darstellung des vollständig qualifizierten Namens der Klasse verwendet wird. Der Indexwert der Klasse ist wie in der folgenden Abbildung dargestellt:
Wie aus der obigen Abbildung deutlich hervorgeht, beträgt der Klassenindexwert 0 × 0003, was der dritten Konstante des Konstantenpools entspricht. Durch das Javap-Ergebnis wissen wir, dass die dritte Konstante eine Konstante vom Typ CONSTANT_Class_info ist wodurch wir die vollständigen Details der Klasse erfahren können. Der qualifizierte Name lautet: com/ejushang/TestClass /TestClass
7) u2 super_class stellt den Indexwert der übergeordneten Klasse der aktuellen Klasse dar. Der Indexwert zeigt auf eine Konstante vom Typ CONSTANT_Class_info. Der Indexwert der übergeordneten Klasse ist wie in der folgenden Abbildung dargestellt 0×0004. Überprüfen Sie die ersten vier Konstanten des Konstantenpools. Es ist ersichtlich, dass der vollständig qualifizierte Name der übergeordneten Klasse von TestClass lautet: java/lang/Object
8) interfaces_count und interfaces[interfaces_count] stellen die Anzahl der Schnittstellen und jede spezifische Schnittstelle dar. Die Anzahl der Schnittstellen und Schnittstellen von TestClass ist in der folgenden Abbildung dargestellt, wobei 0 × 0001 bedeutet, dass die Anzahl der Schnittstellen 1 und 0 × beträgt 0005 bedeutet, dass der Index der Schnittstelle im Konstantenpoolwert die fünfte Konstante im Konstantenpool findet. Ihr Typ ist CONSTANT_Class_info und ihr Wert ist: com/ejushang/TestClass/Super
9) „fields_count“ und „field_info“ , „fields_count“ stellt die Anzahl der field_info-Tabellen in der Klasse dar und „field_info“ stellt die Instanzvariablen und Klassenvariablen der Klasse dar. Dabei ist zu beachten, dass „field_info“ keine von der übergeordneten Klasse geerbten Felder enthält field_info ist wie in der folgenden Abbildung dargestellt:
Unter diesen stellt access_flags das Zugriffsflag des Felds dar, z. B. öffentlich, privat, geschützt, statisch, endgültig usw. Der Wert von access_flags ist in der folgenden Abbildung dargestellt:
Unter diesen sind name_index und descriptor_index beide Indexwerte des Konstantenpools, die jeweils den Namen des Feldes und den Deskriptor des Feldes darstellen. Der Name des Feldes ist leicht zu verstehen, aber wie ist der Deskriptor des Feldes zu verstehen? Feld? Tatsächlich werden in der JVM-Spezifikation die Felddeskriptoren wie in der folgenden Abbildung dargestellt angegeben:
Unter diesen muss jeder auf die letzte Zeile des Bildes achten. Sie stellt den Deskriptor für ein eindimensionales Array dar. Der Deskriptor für String[][] ist [[ Ljava/lang/String und die Beschreibung für int[][] Das Symbol ist [[I. Die folgenden Attribute_Count und Attribute_Info stellen die Anzahl der Attributtabellen bzw. Attributtabellen dar. Nehmen wir die obige TestClass als Beispiel und schauen uns die Feldtabelle von TestClass an.
Schauen wir uns zunächst die Anzahl der Felder in TestClass an, wie in der folgenden Abbildung dargestellt:
Wie aus dem Bild oben hervorgeht, verfügt TestClass über zwei Felder. Wenn wir uns den Quellcode von TestClass ansehen, sehen wir uns als Nächstes das erste Feld an private int staticVar, die Die binäre Darstellung in der Klassendatei ist wie folgt:
Unter diesen stellt 0x001A das Zugriffsflag dar. Anhand der Tabelle access_flags können wir erkennen, dass es sich um ACC_PRIVATE, ACC_STATIC und ACC_FINAL handelt. Als nächstes stellen 0x0006 und 0x0007 die 6. bzw. 7. Konstante im Konstantenpool dar Wenn wir uns den Konstantenpool ansehen, können wir erkennen, dass ihre Werte sind: staticVar und I, wobei staticVar der Feldname und I der Felddeskriptor ist. Durch die obige Erklärung der Deskriptoren beschreibe ich eine Variable vom Typ int. Als nächstes stellt 0×0001 die Anzahl der Attributtabellen in der Feldtabelle staticVar dar. Aus der obigen Abbildung ist ersichtlich, dass es eine entsprechende Attributtabelle gibt 0×0008 stellt die 8. Konstante im Konstantenpool dar. Wenn Sie sich den Konstantenpool ansehen, können Sie sehen, dass dieses Attribut das ConstantValue-Attribut ist und das Format des ConstantValue-Attributs wie in der folgenden Abbildung dargestellt ist:
Unter diesen drückt attribute_name_index den konstanten Poolindex des Attributnamens aus. In diesem Beispiel ist die attribute_length von ConstantValue eine feste Länge von 2, und konstantValue_index stellt die Referenz im Konstantenpool dar ×0009. Sie können die 9. Konstante anzeigen. Sie stellt eine Konstante vom Typ CONSTANT_Integer_info dar, deren Wert 0 ist.
Abgesehen davon, dass private static final int staticVar=0 ist, sprechen wir über private int InstanzVar=0 von TestClass. In diesem Beispiel ist die binäre Darstellung von InstanzVar wie in der folgenden Abbildung dargestellt:
Unter diesen bedeutet 0 × 0002, dass die Zugriffsmarkierung ACC_PRIVATE ist, und 0x000A bedeutet, dass der Name des Felds auf die 10. Konstante im Konstantenpool verweist. Wenn Sie sich den Konstantenpool ansehen, können Sie erkennen, dass der Feldname InstanzVar ist 0× 0007 stellt den Deskriptor des Feldes dar, der auf die 7. Konstante im Konstantenpool zeigt. Wenn Sie sich den Konstantenpool ansehen, können Sie erkennen, dass die 7. Konstante I ist, was den Typ der Instanz darstellt Anzahl der Attributtabellen ist 0. .
10) „methods_count“ und „methods_info“ , wobei „methods_count“ die Anzahl der Methoden darstellt und „methods_info“ die Methodentabelle darstellt. Die Struktur der Methodentabelle ist in der folgenden Abbildung dargestellt:
Wie aus der obigen Abbildung ersichtlich ist, sind die Strukturen von method_info und field_info sehr ähnlich. Alle Flag-Bits und Werte von access_flag in der Methodentabelle sind in der folgenden Abbildung dargestellt:
Unter diesen stellen name_index und descriptor_index den Namen und den Deskriptor der Methode dar und sind Indizes, die jeweils auf den Konstantenpool verweisen. Hier müssen wir den Methodendeskriptor erklären: (Parameterliste) Rückgabewert: Der Deskriptor der öffentlichen int-Instanz (int param) lautet beispielsweise: (I) I, was bedeutet, dass er einen int hat Typparameter. Und der Rückgabewert ist auch eine Methode vom Typ int. Als nächstes gibt es die Anzahl der Attribute und die Attributtabelle anders. Schauen wir uns als Nächstes die binäre Darstellung der Methodentabelle mithilfe von TestClass an. Schauen wir uns zunächst die Anzahl der Methodentabellen an. Der Screenshot sieht wie folgt aus:
Wie aus der obigen Abbildung ersichtlich ist, beträgt die Anzahl der Methodentabellen 0 × 0002, was bedeutet, dass es zwei Methoden gibt. Schauen wir uns als Nächstes die erste Methode an: access_flag, name_index und descriptor_index . Der Screenshot sieht wie folgt aus:
Aus der obigen Abbildung können wir erkennen, dass access_flags 0×0001 ist. Aus der obigen Beschreibung des access_flags-Flags können wir ersehen, dass der Wert von access_flags der Methode ACC_PUBLIC ist und der name_index 0x000B ist. Die 11. Konstante, wissend, dass der Name der Methode <init> ist, bedeutet 0x000C, dass descriptor_index die 12. Konstante im Konstantenpool bedeutet und ihr Wert ()V ist, was bedeutet, dass die <init>-Methode keine Parameter und keinen Rückgabewert hat. Tatsächlich ist dies die vom Compiler automatisch generierte Instanzkonstruktormethode. Das nächste 0×0001 zeigt an, dass die Methodentabelle der <init>-Methode 1 Attribut hat. Der Attribut-Screenshot lautet wie folgt:
Wie aus der obigen Abbildung ersichtlich ist, ist die Konstante im Konstantenpool, die 0x000D entspricht, Code, der das Code-Attribut der Methode darstellt. Hier sollte also jeder verstehen, dass die Codes der Methode im Code-Attribut des Attributs gespeichert sind Tabelle in der Methodentabelle der Klassendatei. Als nächstes analysieren wir das Code-Attribut. Die Struktur des Code-Attributs ist in der folgenden Abbildung dargestellt:
Unter diesen zeigt attribute_name_index auf die Konstante, deren Wert Code im Konstantenpool ist, und die Länge von attribute_length gibt die Länge der Code-Attributtabelle an (es ist zu beachten, dass die Länge nicht die 6-Byte-Länge von attribute_name_index und attribute_length enthält). ).
max_stack stellt die maximale Stapeltiefe dar. Die virtuelle Maschine weist die Tiefe der Operanden im Stapelrahmen basierend auf diesem Wert zur Laufzeit zu, und max_locals stellt den Speicherplatz der lokalen Variablentabelle dar.
Die Einheit von max_locals ist Slot, die kleinste Einheit, mit der die virtuelle Maschine Speicher für lokale Variablen zuweist. Zur Laufzeit belegen Datentypen, die 32-Bit-Typen wie Byte, Char, Int usw. nicht überschreiten, 1 Schlitz, während doppelt und lang Ein 64-Bit-Datentyp muss 2 Slots zuweisen. Darüber hinaus ist der Wert von max_locals nicht die Summe des von allen lokalen Variablen benötigten Speichers, da Slots wiederverwendet werden können Der belegte Steckplatz wird wiederverwendet.
code_length stellt die Anzahl der Bytecode-Anweisungen dar, und code stellt Bytecode-Anweisungen dar. Aus der obigen Abbildung können wir erkennen, dass der Codetyp u1 ist. Der Wert eines u1-Typs ist 0×00-0xFF und die entsprechende Dezimalzahl ist 0-. 255. Derzeit sind in der Spezifikation für virtuelle Maschinen mehr als 200 Anweisungen definiert.
Ausnahmetabellenlänge und Ausnahmetabelle repräsentieren jeweils die Ausnahmeinformationen, die der Methode entsprechen.
attributes_count und attribute_info stellen die Anzahl der Attribute bzw. die Attributtabelle im Code-Attribut dar. Daraus ist ersichtlich, dass die Attributtabelle in der Dateistruktur der Klasse sehr flexibel ist. Sie kann in der Klassendatei, der Methodentabelle und dem Feld vorhanden sein Tabelle und Code-Attribut.
Als nächstes analysieren wir das obige Beispiel weiter. Aus dem Screenshot des Code-Attributs der obigen Init-Methode können wir ersehen, dass die Länge der Attributtabelle 0×00000026 beträgt, der Wert von max_stack 0×0002 ist und der Wert von max_locals ist 0× 0001, die Länge von code_length ist 0x0000000A, dann 00000149h- 00000152h ist Bytecode. Die Länge von „Exception_table_length“ beträgt 0 × 0001 und der Wert von „attribute_count“ beträgt 0 × 000E, was den Namen des Attributs im Konstantenpool darstellt um den 14. zu erhalten. Der Wert der Konstante ist LineNumberTable, LineNu mberTable wird verwendet, um die Entsprechung zwischen der Java-Quellcode-Zeilennummer und der Bytecode-Zeilennummer zu beschreiben. Es ist kein erforderliches Attribut zur Laufzeit, wenn Sie die Generierung dieser Informationen über den Compiler-Parameter -g:none abbrechen Wenn eine Ausnahme auftritt, kann die Fehlerzeilennummer nicht auf dem Stapel angezeigt werden und es können beim Debuggen keine Haltepunkte gemäß dem Quellcode festgelegt werden. Schauen wir uns als Nächstes die Struktur von LineNumberTable an, wie unten gezeigt:
Unter diesen wurde oben erwähnt, dass attribute_name_index den Index des Konstantenpools darstellt, attribute_length die Attributlänge darstellt und die Tabellen start_pc und line_number die Zeilennummer des Bytecodes und die Zeilennummer des Quellcodes darstellen. Der Bytestrom der LineNumberTable-Eigenschaft in diesem Beispiel sieht wie folgt aus:
Nachdem wir die erste Methode von TestClass oben analysiert haben, können wir die zweite Methode von TestClass auf die gleiche Weise analysieren. Der Screenshot sieht wie folgt aus:
Unter diesen ist access_flags 0×0001, name_index 0x000F und descriptor_index 0×0010. Wenn Sie sich den Konstantenpool ansehen, können Sie erkennen, dass es sich bei dieser Methode um die öffentliche int-InstanceMethod-Methode (int param) handelt. Durch eine ähnliche Methode wie oben können wir erkennen, dass das Code-Attribut von „instanceMethod“ wie in der folgenden Abbildung dargestellt ist:
Lassen Sie uns abschließend die Attribute der Klassendatei analysieren. Von 00000191h bis 00000199h handelt es sich um die Attributtabelle in der Klassendatei. Wenn wir uns den Konstantenpool ansehen, können wir erkennen, dass der Attributname SourceFile ist Schauen wir uns die Struktur von SourceFile wie folgt an:
Unter diesen ist attribute_length die Länge des Attributs und sourcefile_index zeigt auf die Konstante im Konstantenpool, deren Wert der Name der Quellcodedatei ist. In diesem Beispiel sieht der Screenshot des SourceFile-Attributs wie folgt aus:
Darunter ist attribute_length 0×00000002, was bedeutet, dass die Länge 2 Bytes beträgt und der Wert von sourcefile_index 0×0012 ist. Wenn Sie sich die 18. Konstante im Konstantenpool ansehen, können Sie erkennen, dass der Name der Quellcodedatei TestClass ist .Java
Abschließend hoffe ich, dass Freunde, die sich für Technologie interessieren, mehr kommunizieren können. Persönliches Weibo: (http://weibo.com/xmuzyq)