Java-Klassendatei

AbschnitteBearbeiten

Die Struktur der Java-Klassendatei besteht aus 10 grundlegenden Abschnitten:

  • Magic Number: 0xCAFEBABE
  • Version des Klassendateiformats: die Minor- und Major-Version der Klassendatei
  • Constant Pool: Pool von Konstanten für die Klasse
  • Zugriffsflags: z.B. ob die Klasse abstrakt, statisch usw. ist
  • Diese Klasse: Der Name der aktuellen Klasse
  • Superklasse: Der Name der Superklasse
  • Interfaces: Alle Schnittstellen in der Klasse
  • Felder: Alle Felder in der Klasse
  • Methoden: Beliebige Methoden in der Klasse
  • Attribute: Alle Attribute der Klasse (z. B. der Name der Quelldatei usw.)

Magic NumberEdit

Klassendateien werden durch den folgenden 4-Byte-Header (in Hexadezimal) gekennzeichnet: CA FE BA BE (die ersten 4 Einträge in der folgenden Tabelle). Die Geschichte dieser magischen Zahl wurde von James Gosling erklärt, der sich auf ein Restaurant in Palo Alto bezog:

„Wir gingen früher zum Mittagessen in ein Lokal namens St. Michael’s Alley. Laut einer lokalen Legende traten dort in der dunklen Vergangenheit die Grateful Dead auf, bevor sie groß rauskamen. Es war ein ziemlich abgefahrener Ort, der definitiv eine Art Grateful Dead Place war. Als Jerry starb, errichteten sie sogar einen kleinen buddhistischen Schrein. Wenn wir dort hingingen, nannten wir den Ort Cafe Dead. Irgendwann ist mir aufgefallen, dass das eine HEX-Zahl ist. Ich war gerade dabei, den Code für ein Dateiformat zu überarbeiten und brauchte ein paar magische Zahlen: eine für die persistente Objektdatei und eine für Klassen. Ich benutzte CAFEDEAD für das Objektdateiformat, und bei der Suche nach 4-Zeichen-Hex-Wörtern, die nach „CAFE“ passten (das schien ein gutes Thema zu sein), stieß ich auf BABE und beschloss, es zu benutzen, was zu diesem Zeitpunkt weder besonders wichtig noch dazu bestimmt schien, irgendwo anders als im Mülleimer der Geschichte zu landen. So wurde CAFEBABE das Klassendateiformat und CAFEDEAD das Format für persistente Objekte. Aber die Möglichkeit, persistente Objekte zu erstellen, wurde abgeschafft, und damit auch die Verwendung von CAFEDEAD – es wurde schließlich durch RMI ersetzt.

Allgemeines LayoutEdit

Da die Klassendatei Elemente mit variabler Größe und keine eingebetteten Datei-Offsets (oder Zeiger) enthält, wird sie in der Regel sequentiell geparst, vom ersten Byte bis zum Ende. Auf der untersten Ebene wird das Dateiformat anhand einiger grundlegender Datentypen beschrieben:

  • u1: eine vorzeichenlose 8-Bit-Ganzzahl
  • u2: eine vorzeichenlose 16-Bit-Ganzzahl in Big-Endian-Byte-Reihenfolge
  • u4: eine vorzeichenlose 32-Bit-Ganzzahl in Big-Endian-Byte-Reihenfolge
  • table: ein Array von Elementen variabler Länge eines bestimmten Typs. Die Anzahl der Elemente in der Tabelle wird durch eine vorangestellte Zählnummer identifiziert (die Zählnummer ist ein u2), aber die Größe der Tabelle in Bytes kann nur durch die Untersuchung der einzelnen Elemente bestimmt werden.

Einige dieser Grundtypen werden dann je nach Kontext als Werte höherer Ebene (wie Zeichenketten oder Gleitkommazahlen) neu interpretiert.es gibt keine Erzwingung der Wortausrichtung, und daher werden keine Auffüllungsbytes verwendet.das Gesamtlayout der Klassendatei ist in der folgenden Tabelle dargestellt.

Byte Offset Größe Typ oder Wert Beschreibung
0 4 Bytes u1 =
0xCA hex
magische Zahl (CAFEBABE), die verwendet wird, um die Datei als konform mit dem Klassendateiformat zu identifizieren
1 u1 =
0xFE hex
2 u1 =
0xBA hex
3 u1 =
0xBE hex
4 2 Bytes u2 kleine Versionsnummer des
5
6 2 Bytes u2 Hauptversionsnummer des verwendeten Klassendateiformats.

Java SE 17 = 61 (0x3D hex),
Java SE 16 = 60 (0x3C hex),
Java SE 15 = 59 (0x3B hex),
Java SE 14 = 58 (0x3A hex),
Java SE 13 = 57 (0x39 hex),
Java SE 12 = 56 (0x38 hex),
Java SE 11 = 55 (0x37 hex),
Java SE 10 = 54 (0x36 hex),
Java SE 9 = 53 (0x35 hex),
Java SE 8 = 52 (0x34 hex),
Java SE 7 = 51 (0x33 hex),
Java SE 6.0 = 50 (0x32 hex),
Java SE 5.0 = 49 (0x31 hex),
JDK 1.4 = 48 (0x30 hex),
JDK 1.3 = 47 (0x2F hex),
JDK 1.2 = 46 (0x2E hex),
JDK 1.1 = 45 (0x2D hex).
Für Details zu früheren Versionsnummern siehe Fußnote 1 unter The JavaTM Virtual Machine Specification 2nd edition

7
8 2 Bytes u2 constant pool count, Anzahl der Einträge in der folgenden Konstantenpooltabelle. Diese Anzahl ist mindestens um eins größer als die tatsächliche Anzahl der Einträge; siehe folgende Diskussion.
9
10 cpsize (variabel) table constant pool table, ein Array von Konstanten-Pool-Einträgen variabler Größe, die Elemente wie Literalzahlen, Strings und Referenzen auf Klassen oder Methoden enthalten. Indiziert ab 1, enthält (Konstanten-Pool-Anzahl – 1) Anzahl der Einträge insgesamt (siehe Hinweis).
10+cpsize 2 bytes u2 Zugriffsflags, eine Bitmaske
11+cpsize
12+cpsize 2 Bytes u2 identifiziert diese Klasse, Index in den Konstanten-Pool zu einem „Class“-Eintrag
13+cpsize
14+cpsize 2 Bytes u2 identifiziert Superklasse, Index in den Konstanten-Pool zu einem Eintrag vom Typ „Klasse“
15+cpsize
16+cpsize 2 Bytes u2 Schnittstellenanzahl, Anzahl der Einträge in der folgenden Schnittstellentabelle
17+cpsize
18+cpsize isize (variabel) table interface table: ein Array mit variabler Länge von konstanten Pool-Indizes, die die von dieser Klasse implementierten Schnittstellen beschreiben
18+cpsize+isize 2 bytes u2 Feldanzahl, Anzahl der Einträge in der folgenden Feldtabelle
19+cpsize+isize
20+cpsize+isize fsize (variable) Tabelle Feldtabelle, Array variabler Länge von Feldern

jedes Element ist eine field_info-Struktur, definiert in https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.5

20+cpsize+isize+fsize 2 bytes u2 method count, Anzahl der Einträge in der folgenden Methodentabelle
21+cpsize+isize+fsize
22+cpsize+isize+fsize msize (variabel) table method table, Array variabler Länge von Methoden

jedes Element ist eine method_info-Struktur, definiert in https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.6

22+cpsize+isize+fsize+msize 2 Bytes u2 Attributanzahl, Anzahl der Einträge in der folgenden Attributtabelle
23+cpsize+isize+fsize+msize
24+cpsize+isize+fsize+msize asize (variabel) table Attributtabelle, Array variabler Länge von Attributen

jedes Element ist eine attribute_info-Struktur, definiert in https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.7

Darstellung in einer C-ähnlichen ProgrammierspracheBearbeiten

Da C keine Arrays mit mehreren variablen Längen innerhalb einer Struktur unterstützt, lässt sich der folgende Code nicht kompilieren und dient nur zur Demonstration.

struct Class_File_Format { u4 magic_number; u2 minor_version; u2 major_version; u2 constant_pool_count; cp_info constant_pool; u2 access_flags; u2 this_class; u2 super_class; u2 interfaces_count; u2 interfaces; u2 fields_count; field_info fields; u2 methods_count; method_info methods; u2 attributes_count; attribute_info attributes;}

Der KonstantenpoolBearbeiten

In der Konstantenpooltabelle werden die meisten literalen konstanten Werte gespeichert. Dazu gehören Werte wie Zahlen aller Art, Zeichenketten, Bezeichnernamen, Verweise auf Klassen und Methoden sowie Typdeskriptoren. Alle Indizes oder Verweise auf bestimmte Konstanten in der Konstanten-Pool-Tabelle werden durch 16-Bit-Zahlen (Typ u2) angegeben, wobei sich der Indexwert 1 auf die erste Konstante in der Tabelle bezieht (der Indexwert 0 ist ungültig).

Aufgrund historischer Entscheidungen, die während der Entwicklung des Dateiformats getroffen wurden, entspricht die Anzahl der Konstanten in der Konstanten-Pool-Tabelle nicht der Anzahl der Konstanten, die der Tabelle vorangestellt ist. Erstens beginnt der Index der Tabelle bei 1 (und nicht bei 0), aber die Anzahl sollte eigentlich als maximaler Index plus 1 interpretiert werden. Außerdem belegen zwei Arten von Konstanten (longs und doubles) zwei aufeinanderfolgende Slots in der Tabelle, obwohl der zweite Slot ein Phantom-Index ist, der nie direkt verwendet wird.

Der Typ jedes Elements (Konstante) im Konstanten-Pool wird durch ein anfängliches Byte-Tag identifiziert. Die Anzahl der Bytes, die diesem Tag folgen, und ihre Interpretation hängen dann von dem Tag-Wert ab. Die gültigen Konstantentypen und ihre Tag-Werte sind:

Tag-Byte Zusätzliche Bytes Beschreibung der Konstante Eingeführte Version
1 2+x Bytes
(variabel)
UTF-8 (Unicode) string: eine Zeichenkette, der eine 16-Bit-Zahl (Typ u2) vorangestellt ist, die die Anzahl der Bytes in der unmittelbar folgenden kodierten Zeichenkette angibt (die von der Anzahl der Zeichen abweichen kann). Beachten Sie, dass die verwendete Kodierung nicht wirklich UTF-8 ist, sondern eine leichte Modifikation der Unicode-Standardkodierungsform darstellt. 1.0.2
3 4 Bytes Ganzzahl: eine vorzeichenbehaftete 32-Bit-Zweierkomplementzahl im Big-Endian-Format 1.0.2
4 4 Bytes Float: eine 32-Bit IEEE 754 Gleitkommazahl mit einfacher Genauigkeit 1.0.2
5 8 Bytes Lang: eine vorzeichenbehaftete 64-Bit-Zweierkomplement-Zahl im Big-Endian-Format (belegt zwei Plätze in der Konstanten-Pool-Tabelle) 1.0.2
6 8 Bytes Double: eine 64-Bit-IEEE-754-Gleitkommazahl mit doppelter Genauigkeit (nimmt zwei Slots in der Konstanten-Pool-Tabelle ein) 1.0.2
7 2 Bytes Klassenreferenz: ein Index innerhalb des Konstantenpools zu einem UTF-8-String, der den voll qualifizierten Klassennamen (im internen Format) enthält (Big-Endian) 1.0.2
8 2 Bytes String-Referenz: ein Index innerhalb des Konstanten-Pools auf einen UTF-8-String (auch Big-Endian) 1.0.2
9 4 Bytes Feldreferenz: zwei Indizes innerhalb des Konstantenpools, der erste zeigt auf eine Klassenreferenz, der zweite auf einen Name und Typ Deskriptor. (big-endian) 1.0.2
10 4 bytes Methodenreferenz: zwei Indizes innerhalb des Konstantenpools, wobei der erste auf eine Klassenreferenz, der zweite auf einen Name- und Typdeskriptor zeigt. (big-endian) 1.0.2
11 4 bytes Methodenreferenz der Schnittstelle: zwei Indizes innerhalb des Konstantenpools, wobei der erste auf eine Klassenreferenz, der zweite auf einen Name- und Typdeskriptor zeigt. (big-endian) 1.0.2
12 4 bytes Name und Typdeskriptor: zwei Indizes auf UTF-8-Strings innerhalb des Konstantenpools, wobei der erste einen Namen (Bezeichner) und der zweite einen speziell kodierten Typdeskriptor darstellt. 1.0.2
15 3 Bytes Methodenhandle: diese Struktur wird verwendet, um ein Methodenhandle darzustellen und besteht aus einem Byte des Typdeskriptors, gefolgt von einem Index innerhalb des Konstantenpools. 7
16 2 Bytes Methodentyp: Diese Struktur wird zur Darstellung eines Methodentyps verwendet und besteht aus einem Index innerhalb des Konstantenpools. 7
17 4 Bytes Dynamisch: Diese Struktur wird verwendet, um eine dynamisch berechnete Konstante anzugeben, die durch den Aufruf einer Bootstrap-Methode erzeugt wird. 11
18 4 Bytes InvokeDynamic: wird von einer invokedynamic-Anweisung verwendet, um eine Bootstrap-Methode, den dynamischen Aufrufnamen, die Argument- und Rückgabetypen des Aufrufs und optional eine Folge zusätzlicher Konstanten, die statische Argumente für die Bootstrap-Methode genannt werden, anzugeben. 7
19 2 Bytes Modul: Dies wird verwendet, um ein Modul zu identifizieren. 9
20 2 bytes Paket: wird verwendet, um ein Paket zu identifizieren, das von einem Modul exportiert oder geöffnet wird. 9

Es gibt nur zwei integrale konstante Typen, integer und long. Andere ganzzahlige Typen, die in der Hochsprache vorkommen, wie boolean, byte und short, müssen als ganzzahlige Konstante dargestellt werden.

Klassennamen in Java werden, wenn sie vollständig qualifiziert sind, traditionell durch Punkte getrennt, wie z.B. „java.lang.Object“. Innerhalb der Low-Level-Klassenreferenzkonstanten erscheint jedoch eine interne Form, die stattdessen Schrägstriche verwendet, wie z. B. „java/lang/Object“.

Die Unicode-Strings sind trotz des Namens „UTF-8-String“ nicht wirklich nach dem Unicode-Standard kodiert, obwohl er ähnlich ist. Es gibt zwei Unterschiede (siehe UTF-8 für eine vollständige Diskussion). Der erste besteht darin, dass der Codepunkt U+0000 als Zwei-Byte-Sequenz C0 80 (in Hexadezimalzeichen) anstelle der Standard-Ein-Byte-Kodierung 00 kodiert wird. Der zweite Unterschied besteht darin, dass zusätzliche Zeichen (außerhalb des BMP bei U+10000 und darüber) mit einer Surrogat-Paar-Konstruktion ähnlich wie bei UTF-16 kodiert werden, anstatt direkt mit UTF-8 kodiert zu werden. In diesem Fall wird jedes der beiden Surrogate separat in UTF-8 kodiert. Zum Beispiel wird U+1D11E als 6-Byte-Sequenz ED A0 B4 ED B4 9E kodiert, anstatt der korrekten 4-Byte-UTF-8-Kodierung von F0 9D 84 9E.

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht.