Für unterschiedliche Plattformen gibt es auch unterschiedliche Dateiformate
für compilierte ausführbare binäre Daten. So nutzt z.B. Windows das COFF-Dateiformat
(Common Object File Format) und Linux das ELF-Dateiformat (Executable and Linking
Format). Die Java-Plattform erreicht ihre binäre Kompatibilität zu anderen Plattformen
durch ein universelles Dateiformat für Java-Programme, dem "Class File
Format". Alle Dateien mit der Endung Zunächst soll ausgehend von Listing 4.2 der Methodenbereich
einer Klassendatei innerhalb eines Hexdumps dieser Klassendatei lokalisiert werden.
Dazu wird als erstes das Java-Listing mit Hilfe eines Java-Compilers auf einen
Bytecode abgebildet. Anschließend kann eine Disassemblierung der entstandenen Klassendatei
mit Hilfe des JDK-Tools Listing 4.2. /* BytecodeExample.java */ public class BytecodeExample { public static void method1() { int j = 0; for (int i = 0; i < 10; i++) { j = j + 2; } System.out.println(j); } public static void main(String[] args) { method1(); } } Mit Hilfe des im JDK enthaltenen Compiler > javac BytecodeExample.java Der Java-Compiler > jikes -classpath c:\programme\java\jre\lib\rt.jar BytecodeExample.java Das Archiv
Disassemblieren der Klassendatei mit
Mit Hilfe des Standard-JDK-Tools > javap -c BytecodeExample werden die folgenden Zeilen auf die Konsole ausgegeben: Compiled from "BytecodeExample.java" public class BytecodeExample extends java.lang.Object { public BytecodeExample(); Code: 0: aload_0 1: invokespecial #1; //Method java/lang/Object."<init>":()V 4: return public static void method1(); Code: 0: iconst_0 1: istore_0 2: iconst_0 3: istore_1 4: iload_1 5: bipush 10 7: if_icmpge 20 10: iload_0 11: iconst_2 12: iadd 13: istore_0 14: iinc 1, 1 17: goto 4 20: getstatic #2; //Field java/lang/System.out:Ljava/io/PrintStream; 23: iload_0 24: invokevirtual #3; //Method java/io/PrintStream.println:(I)V 27: return public static void main(java.lang.String[]); Code: 0: invokestatic #4; //Method method1:()V 3: return } Die Ausgabe zeigt, dass neben den in Listing 4.2
definierten zwei Methoden noch ein Default-Konstruktor durch den Compiler erzeugt
wurde, der die Aufgabe hat den parameterlosen Konstruktor der Superklasse
(
Hexadezimale Darstellung der Klassendatei Durch Verwendung eines geeigneten Programms kann der folgende Hexdump von
Abbildung 4.3. Hexadezimale Darstellung der Klassendatei ca fe ba be 00 00 00 31 00 1e 0a 00 06 00 10 09 .......1........ 0 00 11 00 12 0a 00 13 00 14 0a 00 05 00 15 07 00 ................ 16 16 07 00 17 01 00 06 3c 69 6e 69 74 3e 01 00 03 .......<init>... 32 28 29 56 01 00 04 43 6f 64 65 01 00 0f 4c 69 6e ()V...Code...Lin 48 65 4e 75 6d 62 65 72 54 61 62 6c 65 01 00 07 6d eNumberTable...m 64 65 74 68 6f 64 31 01 00 04 6d 61 69 6e 01 00 16 ethod1...main... 80 28 5b 4c 6a 61 76 61 2f 6c 61 6e 67 2f 53 74 72 ([Ljava/lang/Str 96 69 6e 67 3b 29 56 01 00 0a 53 6f 75 72 63 65 46 ing;)V...SourceF 112 69 6c 65 01 00 14 42 79 74 65 63 6f 64 65 45 78 ile...BytecodeEx 128 61 6d 70 6c 65 2e 6a 61 76 61 0c 00 07 00 08 07 ample.java...... 144 00 18 0c 00 19 00 1a 07 00 1b 0c 00 1c 00 1d 0c ................ 160 00 0b 00 08 01 00 0f 42 79 74 65 63 6f 64 65 45 .......BytecodeE 176 78 61 6d 70 6c 65 01 00 10 6a 61 76 61 2f 6c 61 xample...java/la 192 6e 67 2f 4f 62 6a 65 63 74 01 00 10 6a 61 76 61 ng/Object...java 208 2f 6c 61 6e 67 2f 53 79 73 74 65 6d 01 00 03 6f /lang/System...o 224 75 74 01 00 15 4c 6a 61 76 61 2f 69 6f 2f 50 72 ut...Ljava/io/Pr 240 69 6e 74 53 74 72 65 61 6d 3b 01 00 13 6a 61 76 intStream;...jav 256 61 2f 69 6f 2f 50 72 69 6e 74 53 74 72 65 61 6d a/io/PrintStream 272 01 00 07 70 72 69 6e 74 6c 6e 01 00 04 28 49 29 ...println...(I) 288 56 00 21 00 05 00 06 00 00 00 00 00 03 00 01 00 V.!............. 304 07 00 08 00 01 00 09 00 00 00 1d 00 01 00 01 00 ................ 320 00 00 05 2a b7 00 01 b1 00 00 00 01 00 0a 00 00 ...*............ 336 00 06 00 01 00 00 00 03 00 09 00 0b 00 08 00 01 ................ 352 00 09 00 00 00 48 00 02 00 02 00 00 00 1c 03 3b .....H.........; 368 03 3c 1b 10 0a a2 00 0d 1a 05 60 3b 84 01 01 a7 .<........`;.... 384 ff f3 b2 00 02 1a b6 00 03 b1 00 00 00 01 00 0a ................ 400 00 00 00 1a 00 06 00 00 00 06 00 02 00 07 00 0a ................ 416 00 08 00 0e 00 07 00 14 00 0a 00 1b 00 0b 00 09 ................ 432 00 0c 00 0d 00 01 00 09 00 00 00 20 00 00 00 01 ........... .... 448 00 00 00 04 b8 00 04 b1 00 00 00 01 00 0a 00 00 ................ 464 00 0a 00 02 00 00 00 0e 00 03 00 0f 00 01 00 0e ................ 480 00 00 00 02 00 0f ...... 496 In der mittleren Spalte der Hexdump-Darstellung steht ein druckbares
ASCII-Zeichen, falls ein Byte innerhalb der Klassendatei im Bereich von hexadezimal
Bereiche der Klassendatei Eine Klassendatei lässt sich grob in 10 Bereiche unterteilen. Die folgende
Abbildung zeigt diese Unterteilung am Beispiel von Abbildung 4.4. Einteilung der Klassendatei in verschiedene Bereiche. ca fe ba be .. .. .. .. 00 1e 0a .. .. .. .. 09 0 .. .. .. .. 0a .. .. .. .. 0a .. .. .. .. 07 .. 16 .. 07 .. .. 01 .. .. .. .. .. .. .. .. 01 .. .. 32 .. .. .. 01 .. .. .. .. .. .. 01 .. .. .. .. .. 48 .. .. .. .. .. .. .. .. .. .. .. .. 01 .. .. .. 64 .. .. .. .. .. .. 01 .. .. .. .. .. .. 01 .. .. 80 .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. 96 .. .. .. .. .. .. 01 .. .. .. .. .. .. .. .. .. 112 .. .. .. 01 .. .. .. .. .. .. .. .. .. .. .. .. 128 .. .. .. .. .. .. .. .. .. .. 0c .. .. .. .. 07 144 .. .. 0c .. .. .. .. 07 .. .. 0c .. .. .. .. 0c 160 .. .. .. .. 01 .. .. .. .. .. .. .. .. .. .. .. 176 .. .. .. .. .. .. 01 .. .. .. .. .. .. .. .. .. 192 .. .. .. .. .. .. .. .. .. 01 .. .. .. .. .. .. 208 .. .. .. .. .. .. .. .. .. .. .. .. 01 .. .. .. 224 .. .. 01 .. .. .. .. .. .. .. .. .. .. .. .. .. 240 .. .. .. .. .. .. .. .. .. .. 01 .. .. .. .. .. 256 .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. 272 01 .. .. .. .. .. .. .. .. .. 01 .. .. .. .. .. 288 .. .. .. .. .. .. .. .. .. .. .. 00 03 00 01 .. 304 .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. 320 .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. 336 .. .. .. .. .. .. .. .. 00 09 .. .. .. .. .. .. 352 .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. 368 .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. 384 .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. 400 .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. 416 .. .. .. .. .. .. .. .. .. .. .. .. .. .. 00 09 432 .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. 448 .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. 464 .. .. .. .. .. .. .. .. .. .. .. .. 00 01 .. .. 480 .. .. .. .. .. .. 496 Erläuterungen zu den einzelnen Bereichen der Klassendatei: Tabelle 4.1. Einzelne Bereich einer Klassendatei.
Der bisherige Überblick hat die grobe Einteilung der Klassendatei
Die Klassendatei .. .. .. .. .. .. .. .. .. .. .. 00 03 00 01 .. 304 .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. 320 .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. 336 .. .. .. .. .. .. .. .. 00 09 00 0b 00 08 00 01 352 00 09 00 00 00 48 00 02 00 02 00 00 00 1c 03 3b 368 03 3c 1b 10 0a a2 00 0d 1a 05 60 3b 84 01 01 a7 384 ff f3 b2 00 02 1a b6 00 03 b1 00 00 00 01 00 0a 400 00 00 00 1a 00 06 00 00 00 06 00 02 00 07 00 0a 416 00 08 00 0e 00 07 00 14 00 0a 00 1b 00 0b 00 09 432 .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. 448 .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. 464 .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. 480 Der Methodenbereich beginnt mit den beiden Bytes Die Bedeutungen der 86 Bytes, die die Methode Tabelle 4.2. Codierung der Methode
Den Code-Bytes (Bytes 382-409 innerhalb der Klassendatei), die die Methode
Der Methodenbereich unseres Beispiels wurde erläutert, wobei die Bedeutung
der Bytes von Der Konstantenpool der Beispiel-Klassendatei .. .. .. .. .. .. .. .. 00 1e 0a .. .. .. .. 09 0 .. .. .. .. 0a .. .. .. .. 0a .. .. .. .. 07 .. 16 .. 07 .. .. 01 .. .. .. .. .. .. .. .. 01 .. .. 32 .. .. .. 01 .. .. .. .. .. .. 01 .. .. .. .. .. 48 .. .. .. .. .. .. .. .. .. .. .. .. 01 .. .. .. 64 .. .. .. .. .. .. 01 .. .. .. .. .. .. 01 .. .. 80 .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. 96 .. .. .. .. .. .. 01 .. .. .. .. .. .. .. .. .. 112 .. .. .. 01 .. .. .. .. .. .. .. .. .. .. .. .. 128 .. .. .. .. .. .. .. .. .. .. 0c .. .. .. .. 07 144 .. .. 0c .. .. .. .. 07 .. .. 0c .. .. .. .. 0c 160 .. .. .. .. 01 .. .. .. .. .. .. .. .. .. .. .. 176 .. .. .. .. .. .. 01 .. .. .. .. .. .. .. .. .. 192 .. .. .. .. .. .. .. .. .. 01 .. .. .. .. .. .. 208 .. .. .. .. .. .. .. .. .. .. .. .. 01 .. .. .. 224 .. .. 01 .. .. .. .. .. .. .. .. .. .. .. .. .. 240 .. .. .. .. .. .. .. .. .. .. 01 .. .. .. .. .. 256 .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. 272 01 .. .. .. .. .. .. .. .. .. 01 .. .. .. .. .. 288 .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. 304 Aus den ersten beiden Bytes des Konstantenpools (0x001e = 30) kann die Anzahl der nachfolgenden Konstanten ermittelt werden: Anzahl der Konstanten im Pool = 30 - 1 = 29 Nach diesen beiden Bytes beginnt die erste Konstante mit dem Byte Tabelle 4.3. Unterschiedliche Typen von Konstanten im Konstantenpool.
Zwei Punkte in der mittleren Spalte stehen für ein Byte, das dem Marker-Byte folgt. Eine Konstante vom Typ Utf8 speichert eine Zeichenkette und die Länge der Konstanten ist daher abhängig von der Anzahl der Bytes, die für die Codierung der Zeichen erforderlich ist (wird in der Übersicht gekennzeichnet durch "***" bzw. "x"). Die einzelnen Bytes der ersten Konstanten sollen zunächst näher erläutert werden.
Auflösen der 1. Konstanten (Methodenreferenz) Die erste Konstante ist ein Methodenverweis und wird durch die folgenden fünf Bytes repräsentiert (1. Zeile): .. .. .. .. .. .. .. .. .. .. 0a 00 06 00 10 .. 0
1. Konstante: 0a 00 06 00 10
0a --> Methodenreferenz
00 06 --> Klassen-Index (dez. 6)
00 10 --> Name/Typ-Index (dez. 16)
1. Konstante (Methodref): Methode von Klasse #6, Name/Typ #16 Die zweite Zeile im Anschluss ist sozusagen die Entschlüsselung der fünf Bytes der 1. Konstanten. Sie besagt, dass die Methode zu derjenigen Klasse gehört, deren Namen durch die durch die 6. Konstante des Pools erhalten werden kann. Der Name und der Typ (Paramter und Rückgabewert) der Methode werden durch die 16. Konstante im Pool beschrieben. Werden die beiden zuletzt genannten Konstanten herangezogen, um die 1. Konstante weiter aufzulösen, können die nachfolgenden Informationen gewonnen werden (siehe auch weitere Konstanten im Konstantenpool): 1. Konstante --> Methode von Klasse Object Name der Methode: <init> Methodendeskriptor: ()V Die Zeichenfolge Methodendeskriptor. Ein Methodendeskriptor (Deskriptor: Kennwort, Schlüsselwort) ist ein String, der Informationen über die Paramter und den Rückgabewert einer Methode enthält. Er setzt sich aus dem Paramterdeskriptor (ParamterDescriptor) und dem Rückgabewertdeskriptor (ReturnDescriptor) wie folgt zusammen: (ParameterDescriptor*)ReturnDescriptor Der Parameterdeskriptor hat im Beispiel keinen Wert und daher verbleibt
nur das Klammerpaar "()". Die Methode hat also keine Parameter. Für ReturnDescriptor
steht "V". Durch den Buchstaben "V" wird angegeben, dass die Methode keinen Wert
zurückgibt ("V" steht für Die 1. Konstante steht also für den Konstruktor 1. Konstante --> Konstruktor: public Object() Klasse: java.lang.Object Die Superklasse von
Auflösen der 2. Konstanten (Feldreferenz) Nachdem die 1. Konstante im Konstantenpool aufgelöst wurde, soll nun die 2. Konstante, die einen Verweis auf ein Feld beinhaltet, näher untersucht werden (die Variablen einer Klasse werden als Felder (engl. Fields) dieser Klasse bezeichnet): .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. 09 0 00 11 00 12 .. .. .. .. .. .. .. .. .. .. .. .. 16 2. Konstante: 09 00 11 00 12 09 --> Feldreferenz 00 11 --> Klassen-Index (dez. 17) 00 12 --> Name/Typ-Index (dez. 18) 2. Konstante (Fieldref): Feld von Klasse #17, Name/Typ #18 2. Konstante --> Feld von Klasse System Name des Feldes: out Felddeskriptor: Ljava/io/PrintStream; 2. Konstante --> Feld: static PrintStream out Klasse: java.lang.System Die 2. Konstante im Konstantenpool der betrachteten Klassendatei verweist
also auf das Feld Abbildung 4.5. Ausschnitt aus der API-Dokumentation der Klasse Das Feld ist vom Typ
Felddeskriptor. Ein Felddeskriptor ist ebenfalls ein Zeichenkette,
die den Typ des Feldes beschreibt. Neben Referenztypen werden auch weitere Buchstaben
verwendet, falls der Feldtyp ein primitiver Typ ist. Für ein Feld vom Typ
Tabelle 4.4. Schlüsselzeichen innerhalb eines Felddeskriptors.
Die folgenden Beispiele zeigen einige Felder und die zugehörigen Felddeskriptoren, die als mögliche Konstanten (Zeichenketten) innerhalb eines Konstantenpools auftreten können:
An dieser Stelle soll noch eine Methode (drei Parameter und Rückgabewert) und ihr zugehöriger Methodendeskriptor genannt werden: Methodendeklaration: public Object method2(int i, boolean b, String[] sa) { ... } Methodendeskriptor: (IZ[Ljava/lang/String;)Ljava/lang/Object; Der Methodendeskriptor enthält die drei Felddeskriptoren der einzelnen
Parameter der Methode innerhalb des Klammerpaares. Der Felddeskriptor des
Rückgabewertes
Konstante vom Typ Class Innerhalb der 1. Konstanten 1. Konstante (Methodref): Methode von Klasse #6, Name/Typ #16 wird durch die Angabe des Index #6 auf die 6. Konstante im Konstantenpool verwiesen. Diese Konstante ist vom Typ Class und lautet: .. 07 00 17 .. .. .. .. .. .. .. .. .. .. .. .. 32
6. Konstante: 07 00 17
07 --> Konstante vom Typ Class
00 17 --> Index im Konstantenpool (dez. 23)
(Name der Klasse)
6. Konstante (Class): Klasse #23 Eine Konstante vom Typ Class besteht nach Tabelle 4.3 aus insgesamt drei Bytes, wobei die beiden letzten Bytes einen Index im Konstantenpool festlegen.
Konstante vom Typ NameAndType Die 1. Konstante verweist durch die Angabe #16 auf eine weitere Konstante, auf die 16. Konstante vom Typ NameAndType. .. .. .. .. .. .. .. .. .. .. 0c 00 07 00 08 .. 144
16. Konstante: 0c 00 07 00 08
0c --> Konstante vom Typ NameAndType
00 07 --> Index im Konstantenpool
(Name der der Methode)
00 08 --> Index im Konstantenpool
(Methodendeskriptor)
16. Konstante (NameAndType): Name #7, Typ #8 Eine Konstante vom Typ NameAndType besteht aus fünf Bytes, wobei jeweils zwei Bytes einen Index im Konstantenpool codieren. Die durch diese Indizes adressierten Konstanten sind jeweils vom Typ Utf8.
Konstante vom Typ Utf8 Eine Konstante vom Typ Utf8 speichert eine Zeichenkette bestehend aus Unicode-Zeichen mit der Zeichencodierung UTF-8 (8-bit Unicode Transformation Format). Als Beispiel für ein Konstante vom Typ Utf8 soll die 8. Konstante dienen: .. .. .. .. .. .. .. .. .. .. .. .. .. 01 00 03 32 28 29 56 .. .. .. .. .. .. .. .. .. .. .. .. .. 48 8. Konstante: 01 00 03 28 29 56 01 --> Konstante vom Typ Utf8 00 03 --> Anzahl der nachfolgenden Bytes, die noch zur Konstanten gehören 28 --> Zahlencodierung für das Zeichen "(" 29 --> Zahlencodierung für das Zeichen ")" 56 --> Zahlencodierung für das Zeichen "V" 8. Konstante (Utf8): ()V Die 8. Konstante ist im Beispiel der Methodendeskriptor des durch den Compiler erzeugten Default-Konstruktors.
Konstante vom Typ String In der zu Listing 4.2 gehörenden Klassendatei
String str = "Hallo"; innerhalb des Beispiel-Quelltextes hätte zur Folge, dass der Compiler bei
der Übersetzung in die Klassendatei eine entrechende Konstante vom Typ String
erzeugt. Nach Tabelle 4.3 beginnt eine Konstante diesen
Typs mit
Konstanten vom Typ Integer und Float Konstanten vom Typ Integer und Float innerhalb des Konstantenpools von
int ivar = 32768; float fvar = 1.23e12f; zusätzlich eingetragen wären. Eine Initialisierung der Variablen
Konstanten vom Typ Long und Double Durch zusätzliches Einfügen der Instanzvariablen long lvar = 123; double dvar = 2.34e23d; in den Quelltext aus Listing 4.2 werden durch
den Java-Compiler zusätzliche Konstanten vom Typ Long und Double in den Konstantenpool
von 05 00 00 00 00 00 00 00 7b 06 44 c8 c6 95 2c 6b 6e bf Die erste Bytefolge codiert die Zahl 123 im Konstantenpool und die zweite Reihe steht für die Gleitkommazahl 2.34e23. Konstanten vom Typ Long und Double belegen zwei Einträge im Konstantenpool (Definition bzw. Festlegung der Java-Entwickler). Steht z.B. eine Konstante vom Typ Long an 2. Stelle im Pool wird die nächste Konstante mit 4 nummeriert. Die Festlegung, dass Konstanten vom Typ Long und Double zwei Einträge im Konstantenpool belegen, wird innerhalb der "Java Virtual Machine Specification, Second Edition" wie folgt kommentiert (Zitat): "In retrospect, making 8-byte constants take two constant pool entries was a poor choice."
Konstante vom Typ InterfaceMethodref Eine Konstante vom Typ InterfaceMethodref besteht ebenfalls wie eine Konstante
vom Typ Methodref aus insgesamt fünf Bytes. Nach dem Byte
Auflistung der Konstanten im Konstantenpool Die bisher erarbeiteten Kenntnisse über den Aufbau eines Konstantenpools
und die darin enthaltenen unterschiedlichen Typen von Konstanten können nun genutzt
werden, um ein kurzes Beispielprogramm zu entwickeln, das die einzelnen Konstanten
eines Pools aus einer Klassendatei ausliest und auf dem Bildschirm ausgibt. Vor
dem Konstantenpool stehen immmer 8 Bytes und der zu analysierende Byte-Block
beginnt damit mit Byte 8 (die Position der Bytes beginnt mit 0). Nach der Auswertung
von Byte 8 und 9 ist die Anzahl der im Pool enthaltenen Konstanten ermittelt und
mit Byte 10 beginnt die 1. Konstante. Mit dem erste Marker-Byte (tag byte) an
Position 10 ist auch die Länge der 1. Konstanten bekannt, falls diese nicht den
Wert Listing 4.3. /* AnalyzeConstantpool.java */ import java.io.*; public class AnalyzeConstantpool { public static void getConstants(FileInputStream stream, int length) { int i = 0; int data; int[] dump = new int[length]; try { while ((data = stream.read()) != -1) { dump[i] = data; i++; } } catch (IOException e) { System.out.println(e.toString()); } boolean classFile = (dump[0] == 0xca) && (dump[1] == 0xfe) && (dump[2] == 0xba) && (dump[3] == 0xbe); if (!classFile) { System.out.println("Keine class-Datei!"); System.exit(1); } // Anzahl der Konstanten im Pool int cpSize = ((dump[8] << 8) | dump[9]) - 1; System.out.println("Es sind " + cpSize + " Konstanten im Konstantenpool enthalten."); // Konstanten int k = 10; // 1. Konstante beginnt bei Byte 10 for (int j = 1; j <= cpSize; j++) { switch (dump[k]) { // CONSTANT_Class, 3 Bytes case 0x07: System.out.println(j + ". Konstante (Class): " + "Klasse #" + ((dump[k+1] << 8) | dump[k+2])); k = k + 3; break; // CONSTANT_Fieldref, 5 Bytes case 0x09: System.out.println(j + ". Konstante (Fieldref): " + "Feld von Klasse #" + ((dump[k+1] << 8) | dump[k+2]) + ", Name/Typ #" + ((dump[k+3] << 8) | dump[k+4])); k = k + 5; break; // CONSTANT_Methodref, 5 Bytes case 0x0a: System.out.println(j + ". Konstante (Methodref): " + "Methode von Klasse #" + ((dump[k+1] << 8) | dump[k+2]) + ", Name/Typ #" + ((dump[k+3] << 8) | dump[k+4])); k = k + 5; break; // CONSTANT_InterfaceMethodref, 5 Bytes case 0x0b: System.out.println(j + ". Konstante (InterfaceMethodref): " + "Interface-Methode von Klasse #" + ((dump[k+1] << 8) | dump[k+2]) + ", Name/Typ #" + ((dump[k+3] << 8) | dump[k+4])); k = k + 5; break; // CONSTANT_String, 3 Bytes case 0x08: System.out.println(j + ". Konstante (String): " + "String #" + ((dump[k+1] << 8) | dump[k+2])); k = k + 3; break; // CONSTANT_Integer, 5 Bytes case 0x03: System.out.println(j + ". Konstante (Integer): " + ((dump[k+1] << 24) | (dump[k+2] << 16) | (dump[k+3] << 8) | dump[k+4])); k = k + 5; break; // CONSTANT_Float, 5 Bytes case 0x04: int bitsI = (dump[k+1] << 24) | (dump[k+2] << 16) | (dump[k+3] << 8) | dump[k+4]; float f = Float.intBitsToFloat(bitsI); System.out.println(j + ". Konstante (Float): " + f); k = k + 5; break; // CONSTANT_Long, 9 Bytes case 0x05: long l = ((long)dump[k+1] << 56) | ((long)dump[k+2] << 48) | ((long)dump[k+3] << 40) | ((long)dump[k+4] << 32) | ((long)dump[k+5] << 24) | ((long)dump[k+6] << 16) | ((long)dump[k+7] << 8) | (long)dump[k+8]; System.out.println(j + ". Konstante (Long): " + l); k = k + 9; j = j + 1; System.out.println(j + ". Konstante: Konstanten vom Typ Long belegen " + "2 Konstanten im Konstantenpool!"); break; // CONSTANT_Double, 9 Bytes case 0x06: long ld = ((long)dump[k+1] << 56) | ((long)dump[k+2] << 48) | ((long)dump[k+3] << 40) | ((long)dump[k+4] << 32) | ((long)dump[k+5] << 24) | ((long)dump[k+6] << 16) | ((long)dump[k+7] << 8) | (long)dump[k+8]; double d = Double.longBitsToDouble(ld); System.out.println(j + ". Konstante (Double): " + d); k = k + 9; j = j + 1; System.out.println(j + ". Konstante: Konstanten vom Typ Double belegen " + "2 Konstanten im Konstantenpool!"); break; // CONSTANT_NameAndType, 5 Bytes case 0x0c: System.out.println(j + ". Konstante (NameAndType): " + "Name #" + ((dump[k+1] << 8) | dump[k+2]) + ", Typ #" + ((dump[k+3] << 8) | dump[k+4])); k = k + 5; break; // CONSTANT_Utf8, 2 Bytes + utf8Length Bytes case 0x01: int utf8Length = (dump[k+1] << 8) | dump[k+2]; System.out.print(j + ". Konstante (Utf8): "); for (int m = 1; m <= utf8Length; m++) { System.out.print((char)dump[k+2+m]); } System.out.println(); k = k + 3 + utf8Length; break; } } } public static void main(String[] args) { if (args.length == 1) { String fileName = args[0]; try { File f = new File(fileName); int l = (int)f.length(); FileInputStream in = new FileInputStream(f); getConstants(in, l); in.close(); } catch (Exception e) { System.out.print(e.toString()); } } else { System.out.println("usage: java AnalyzeConstantpool <filename>\n"); } } } Die Anweisung > java AnalyzeConstantpool BytecodeExample.class führt zur folgenden Ausgabe: Es sind 29 Konstanten im Konstantenpool enthalten. 1. Konstante (Methodref): Methode von Klasse #6, Name/Typ #16 2. Konstante (Fieldref): Feld von Klasse #17, Name/Typ #18 3. Konstante (Methodref): Methode von Klasse #19, Name/Typ #20 4. Konstante (Methodref): Methode von Klasse #5, Name/Typ #21 5. Konstante (Class): Klasse #22 6. Konstante (Class): Klasse #23 7. Konstante (Utf8): <init> 8. Konstante (Utf8): ()V 9. Konstante (Utf8): Code 10. Konstante (Utf8): LineNumberTable 11. Konstante (Utf8): method1 12. Konstante (Utf8): main 13. Konstante (Utf8): ([Ljava/lang/String;)V 14. Konstante (Utf8): SourceFile 15. Konstante (Utf8): BytecodeExample.java 16. Konstante (NameAndType): Name #7, Typ #8 17. Konstante (Class): Klasse #24 18. Konstante (NameAndType): Name #25, Typ #26 19. Konstante (Class): Klasse #27 20. Konstante (NameAndType): Name #28, Typ #29 21. Konstante (NameAndType): Name #11, Typ #8 22. Konstante (Utf8): BytecodeExample 23. Konstante (Utf8): java/lang/Object 24. Konstante (Utf8): java/lang/System 25. Konstante (Utf8): out 26. Konstante (Utf8): Ljava/io/PrintStream; 27. Konstante (Utf8): java/io/PrintStream 28. Konstante (Utf8): println 29. Konstante (Utf8): (I)V Die Variablen einer Klasse werden als die Felder der Klasse bezeichnet
(Klassenvariablen, Instanzvariablen). Ein minimaler Feldbereich einer Klassendatei
besteht aus den beiden Bytes String str = "Hallo"; int ivar = 32768; static double dvar = 2.34e23d; private static final int jconst = 3; dann besteht der zugehörige Feldbereich aus insgesamt 41 Bytes: 00 04 00 00 .. .. .. .. 00 00 00 00 .. .. .. .. 00 00 00 08 .. .. .. .. 00 00 00 1a .. .. .. .. 00 01 .. .. 00 00 00 02 .. .. Die beiden Bytes
Die Namensbezeichnungen der Flags wie z.B. 00000000 00000010 0x0002 00000000 00001000 0x0008 00000000 00010000 0x0010 ----------------- 00000000 00011010 0x001a Die vier Bytes nach diesen beiden Bytes (access flags) stehen für zwei Indizes
im Konstantenpool der Klassendatei (durch Punkte gekennzeichnet). Die durch diese
Indizes adressierten Konstanten im Pool speichern Informationen zum Feld (Name des
Feldes, Felddeskriptor). Danach folgen zwei Bytes, die die Anzahl der folgenden
Attribute für dieses Feld angeben. Der Byte-Block für das Feld 00 1a .. .. .. .. 00 01 .. .. 00 00 00 02 .. .. Das Feld-Attribut an sich wird repräsentiert durch: .. .. 00 00 00 02 .. .. Die ersten beiden Bytes des Attributs verweisen auf eine Konstante im
Konstantenpool der Klassendatei, mit der der Name des Attributs erhalten werden
kann. Dabei handelt es sich um ein ConstantValue-Attribut (siehe dazu
Abschnitt 4.2.5). Die letzten beiden Bytes verweisen wiederum auf
eine Konstante im Pool vom Typ Integer. Diese Konstante speichert den Wert 3. Die
Bytefolge Attribute (Beifügungen) treten innerhalb unterschiedlicher Bereiche einer Klassendatei auf. Attribute können auch innerhalb eines anderen Attributs auftreten (Attribut eines Attributs). Die Bereiche, in denen Attribute zugelassen sind, lauten:
Die folgende Übersicht nennt definierte Attribute und deren mögliche Verwendung in verschiedenen Abschnitten einer Klassendatei: Tabelle 4.5. Attribute innerhalb einer Klassendatei.
Einige Attribute wie z.B. SourceFile-, LineNumberTable- und
LocalVariableTable-Attribute sind optional und nicht zwingend notwendig. Ein
Klassendatei-Reader einer virtuellen Java-Maschine kann die darin enthaltenen
Informationen auslesen oder auch ignorieren. Dagegen sind Code-, ConstantValue-
und Exceptions-Attribute für die Interpretierung einer Klassendatei durch eine
JVM-Implementierung essentiell. Mit Hilfe der Option |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||