Freunde, die Java lernen, sollten alle wissen, dass Java von Anfang an das Banner der Plattformunabhängigkeit verwendet und sagt: „Einmal schreiben, überall ausführen“. Unabhängigkeit, Java Die Plattform hat auch eine andere Bedeutung: Um Sprachunabhängigkeit zu erreichen, ist die Dateistruktur oder der Bytecode der Klasse im Java-System von Anfang an sehr wichtig Spezifikationen, ist die Java-Sprachspezifikation und die andere ist die Java Virtual Machine-Spezifikation Die Java-Sprachspezifikation legt nur die Einschränkungen und Regeln fest, die sich auf die Java-Sprache beziehen, während dies bei der Virtual Machine-Spezifikation der Fall ist der echte grenzüberschreitende Entwurf aus Plattformperspektive .
Vielleicht denken die meisten Programmierer, dass es für die Java Virtual Machine selbstverständlich und natürlich ist, Java-Programme auszuführen, aber heute haben kommerzielle Organisationen und Open-Source-Organisationen zusätzlich zur Java-Sprache eine große Anzahl von Java-Programmen entwickelt. Sprachen, die auf virtuellen Maschinen laufen, wie Clojure, Groovy, JRuby, Jython, Scale usw. Sie können einen Java-Compiler verwenden, um Java-Code in eine Klassendatei zu kompilieren, die Bytecode speichert. Sie können auch einen Compiler in anderen Sprachen wie JRuby verwenden, um Programmcode in eine Klassendatei zu kompilieren weil die Java Virtual Machine denselben plattformunabhängigen Bytecode laden und ausführen kann. Mit anderen Worten, die Grundlage für die Unabhängigkeit der Sprachplattform ist das Speicherformat der virtuellen Maschine und des Bytecodes. Der virtuellen Maschine ist es egal, aus welcher Sprache die Klasse stammt, solange sie der Struktur der Klassendatei entspricht die Java Virtual Machine.
1) Die Klassendatei besteht aus einem Byte-Stream (8 Bit) , Diese Byteströme sind in strikter Übereinstimmung mit der vorgeschriebenen Reihenfolge angeordnet und es gibt keine Lücken zwischen den Bytes. Daten, die 8 Bytes überschreiten, werden in der Big-Endian-Reihenfolge gespeichert, d. h. in den höherwertigen Bytes werden an niedrigen Adressen gespeichert, und die niederwertigen Bytes werden an hohen Adressen gespeichert. Dies ist tatsächlich auch der Schlüssel zu plattformübergreifenden Klassendateien , da die PowerPC-Architektur die Big-Endian-Speicherreihenfolge verwendet. Während Prozessoren der x86-Serie die Little-Endian-Speicherreihenfolge verwenden, müssen Klassendateien daher unter verschiedenen Prozessorarchitekturen eine einheitliche Speicherreihenfolge beibehalten.
2) Die Klassendateistruktur verwendet eine C-ähnliche Struktur zum Speichern von Daten. Es gibt zwei Haupttypen von Datenelementen: vorzeichenlose Zahlen und Tabellen. Vorzeichenlose Zahlen werden zum Ausdrücken von Zahlen, Indexreferenzen und Zeichenfolgen verwendet usw. Beispielsweise stellen u1, u2, u4, u8 jeweils 1 Byte, 2 Bytes, 4 Bytes und 8 Bytes vorzeichenloser Zahlen dar, und die -Tabelle besteht aus mehreren zusammengesetzten Strukturen von vorzeichenlosen Zahlen und anderen Tabellen . Vielleicht ist sich hier nicht jeder ganz im Klaren darüber, was die vorzeichenlosen Zahlen und Tabellen oben sind, aber das spielt keine Rolle, ich werde es anhand von Beispielen erklären, wenn ich auf die Beispiele unten warte.
Nachdem wir die beiden oben genannten Punkte geklärt haben, werfen wir einen Blick auf die spezifischen Daten, die im Bytestrom enthalten sind und in strenger Reihenfolge in der Klassendatei angeordnet sind:
Beim Betrachten des Bildes oben müssen wir auf eines achten. Beispielsweise stellt cp_info den Konstantenpool dar. Im Bild oben wird Constant_pool[constant_pool_count-1] verwendet, um den Konstantenpool darzustellen Constant_pool_count-1-Konstanten. Es wird hier ein Array-Ausdruck verwendet, aber denken Sie nicht fälschlicherweise, dass die konstanten Längen aller Konstantenpools gleich sind Tatsächlich werden hier Arrays nur zur Vereinfachung der Beschreibung verwendet. Aber hier ist es nicht wie bei einer Programmiersprache. Ein Array vom Typ int hat die gleiche Länge.
1) u4 magic stellt die magische Zahl dar und die magische Zahl belegt 4 Bytes. 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. Virtuelle Maschinen höherer Versionen unterstützen die Klassendateistruktur, die von Compilern niedrigerer Versionen kompiliert wurde. Beispielsweise unterstützt die virtuelle Maschine, die Java SE 6.0 entspricht, die vom Compiler von Java SE 5.0 kompilierte Klassendateistruktur und umgekehrt .
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 Dazu gehören hauptsächlich Zeichenfolgen, der Wert einer Endkonstante oder der Anfangswert einer Eigenschaft usw., während symbolische Referenzen hier hauptsächlich die vollständig qualifizierten Namen von Klassen und Schnittstellen, die Namen und Deskriptoren von Feldern sowie die Namen und Deskriptoren von Methoden speichern Der Name ist möglicherweise für jeden leicht zu verstehen. Was das Konzept der Deskriptoren betrifft, werden wir im Folgenden auf die Feldtabelle und die Methodentabelle eingehen. Darüber hinaus weiß jeder, dass das Speichermodell von JVM aus Heap, Stapel, Methodenbereich und Programmzähler besteht und es im Methodenbereich einen Bereich gibt, der als Laufzeitkonstantenpool bezeichnet wird. Die im Laufzeitkonstantenpool gespeicherten Dinge Tatsächlich werden verschiedene Literale und Symbolreferenzen vom Prozessor generiert, 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. Die im Konstantenpool platzierten Datenelemente enthalten insgesamt 14 Konstanten. Jede Konstante ist eine Tabelle, und jede Konstante verwendet ein gemeinsames Teil-Tag, um anzugeben, um welche Art von Konstante es sich handelt.
Konstantentyp | Wert |
---|---|
CONSTANT_Class td> |
7 |
CONSTANT_Fieldref |
9 | CONSTANT_Methodref |
10 |
CONSTANT_InterfaceMethodref |
11 |
CONSTANT_String |
8 |
CONSTANT_Integer |
3 |
CONSTANT_Float |
4 |
CONSTANT_Long |
5 |
CONSTANT_Double |
6 |
CONSTANT_NameAndType
|
12 |
CONSTANT_Utf8 td> |
1 |
CONSTANT_MethodHandle |
15 | CONSTANT_MethodType |
16 |
CONSTANT_InvokeDynamic |
18 |
6)u2 access_flags 表示类或者接口的访问信息,具体如下图所示:
Flag Name | Value | Interpretation |
---|---|---|
ACC_PUBLIC |
0x0001 | Declared public ; may be accessed from outside its package. |
ACC_FINAL |
0x0010 | Declared final ; no subclasses allowed. |
ACC_SUPER |
0x0020 | Treat superclass methods specially when invoked by the invokespecial instruction. |
ACC_INTERFACE |
0x0200 | Is an interface, not a class. |
ACC_ABSTRACT |
0x0400 | Declared abstract ; must not be instantiated. |
ACC_SYNTHETIC |
0x1000 | Declared synthetic; not present in the source code. |
ACC_ANNOTATION |
0x2000 | Declared as an annotation type. |
ACC_ENUM |
0x4000 | Declared as an enum type. |
7)u2 this_class 表示类的常量池索引,指向常量池中CONSTANT_Class的常量
8)u2 super_class 表示超类的索引,指向常量池中CONSTANT_Class的常量
9)u2 interface_counts 表示接口的数量
10)u2 interface[interface_counts]表示接口表,它里面每一项都指向常量池中CONSTANT_Class常量
11)u2 fields_count 表示类的实例变量和类变量的数量
12) field_info fields[fields_count]表示字段表的信息,其中字段表的结构如下图所示:
field_info { u2 access_flags; u2 name_index; u2 descriptor_index; u2 attributes_count; attribute_info attributes[attributes_count]; }
上图中access_flags表示字段的访问表示,比如字段是public、private、protect 等,name_index表示字段名称,指向常量池中类型是CONSTANT_UTF8的常量,descriptor_index表示字段的描述符,它也指向常量池中类型为 CONSTANT_UTF8的常量,attributes_count表示字段表中的属性表的数量,而属性表是则是一种用与描述字段,方法以及 类的属性的可扩展的结构,不同版本的Java虚拟机所支持的属性表的数量是不同的。
13) u2 methods_count表示方法表的数量
14)method_info 表示方法表,方法表的具体结构如下图所示:
method_info { u2 access_flags; u2 name_index;, u2 descriptor_index; u2 attributes_count; attribute_info attributes[attributes_count]; }
其中access_flags表示方法的访问表示,name_index表示名称的索引,descriptor_index表示方法的描述符,attributes_count以及attribute_info类似字段表中的属性表,只不过字段表和方法表中属性表中的属性是不同的,比如方法表中就有Code属性,表示方法的代码,而字段表中就没有Code属性。
15) attribute_count表示属性表的数量,说到属性表,我们需要明确以下几点:
属性表存在于Class文件结构的最后,字段表,方法表以及Code属性中,也就是说属性表中也可以存在属性表,属性表的长度是不固定的,不同的属性,属性表的长度是不同的
Das obige ist der detaillierte Inhalt vonEinführung in die Klassendateistruktur der Java Virtual Machine. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!