Java class file

SectionsEdit

Er zijn 10 basissecties in de Java class file structuur:

  • Magic Number: 0xCAFEBABE
  • Version of Class File Format: de minor en major versies van het class file
  • Constant Pool: Pool van constanten voor de klasse
  • Access Flags: bijvoorbeeld of de klasse abstract is, statisch, enz.
  • Deze klasse: De naam van de huidige klasse
  • Superklasse: De naam van de superklasse
  • Interfaces: Eventuele interfaces in de klasse
  • Velden: Eventuele velden in de klasse
  • Methoden: Alle methoden in de klasse
  • Attributen: Eventuele attributen van de klasse (bijvoorbeeld de naam van het bronbestand, etc.)

Magic NumberEdit

Klasse bestanden worden geïdentificeerd door de volgende 4 byte header (in hexadecimaal): CA FE BA BE (de eerste 4 regels in de tabel hieronder). De geschiedenis van dit magische getal werd uitgelegd door James Gosling, die verwees naar een restaurant in Palo Alto:

“We gingen vroeger lunchen in een plaats die St Michael’s Alley heette. Volgens een plaatselijke legende trad daar in een ver verleden de Grateful Dead op, voordat ze groot werden. Het was een behoorlijk funky plek die zeker een Grateful Dead Kinda Place was. Toen Jerry stierf, hebben ze er zelfs een klein boeddhistisch heiligdom neergezet. Toen we daar kwamen, noemden we het Cafe Dead. Ergens in de loop van de tijd werd het me duidelijk dat dit een HEX nummer was. Ik was wat bestandsformaat code aan het vernieuwen en had een paar magische nummers nodig: een voor het persistent object bestand, en een voor classes. Ik gebruikte CAFEDEAD voor het object bestandsformaat, en tijdens het zoeken naar 4 karakter hex woorden die pasten na “CAFE” (het leek een goed thema te zijn) kwam ik BABE tegen en besloot het te gebruiken. Op dat moment leek het niet erg belangrijk of voorbestemd om ergens anders heen te gaan dan de prullenbak van de geschiedenis. Dus CAFEBABE werd het klasse bestandsformaat, en CAFEDEAD was het persistente object formaat. Maar de persistente object faciliteit verdween, en daarmee ook het gebruik van CAFEDEAD – het werd uiteindelijk vervangen door RMI.

Algemene layoutEdit

Omdat het klassebestand items van variabele grootte bevat en niet ook ingebedde bestandsoffsets (of pointers) bevat, wordt het typisch sequentieel geparseerd, vanaf de eerste byte naar het einde toe. Op het laagste niveau wordt het bestandsformaat beschreven in termen van een paar fundamentele datatypes:

  • u1: een niet-ondertekend 8-bit geheel getal
  • u2: een niet-ondertekend 16-bit geheel getal in big-endian bytevolgorde
  • u4: een niet-ondertekend 32-bit geheel getal in big-endian bytevolgorde
  • tabel: een array van items van variabele lengte van een of ander type. Het aantal items in de tabel wordt geïdentificeerd door een voorafgaand telgetal (de telling is een u2), maar de grootte in bytes van de tabel kan alleen worden bepaald door elk van de items te onderzoeken.

Enkele van deze fundamentele types worden vervolgens geherinterpreteerd als waarden van een hoger niveau (zoals strings of floating-point getallen), afhankelijk van de context.Er is geen handhaving van woord uitlijning, en dus worden er nooit padding bytes gebruikt.De algemene lay-out van het klassebestand is zoals weergegeven in de volgende tabel.

byte offset size type of waarde description
0 4 bytes u1 =
0xCA hex
magisch getal (CAFEBABE) gebruikt om bestand te identificeren als zijnde conform de class file format
1 u1 =
0xFE hex
2 u1 =
0xBA hex
3 u1 =
0xBE hex
4 2 bytes u2 minor versienummer van de klassebestandsindeling die wordt gebruikt
5
6 2 bytes u2 major versienummer van de klassebestandsindeling die wordt gebruikt.

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).
Voor details over eerdere versienummers zie voetnoot 1 bij The JavaTM Virtual Machine Specification 2nd edition

7
8 2 bytes u2 constant pool count, aantal entries in de volgende constant pool tabel. Deze telling is minstens één groter dan het werkelijke aantal entries; zie de volgende discussie.
9
10 cpsize (variabel) table constantpooltabel, een array van constante pool entries van variabele grootte, die items bevat zoals letterlijke getallen, strings, en verwijzingen naar klassen of methoden. Geïndexeerd beginnend bij 1, met (constant pool count – 1) aantal entries in totaal (zie noot).
10+cpsize 2 bytes u2 access flags, een bitmask
11+cpsize
12+cpsize 2 bytes u2 identificeert deze klasse, index in de constante pool naar een “Class”-type item
13+cpsize
14+cpsize 2 bytes u2 identificeert de superklasse, index in de constante pool naar een “Class”-type entry
15+cpsize
16+cpsize 2 bytes u2 interfacetelling, aantal ingangen in de volgende interfacetabel
17+cpsize
18+cpsize isize (variabel) table interfacetabel: een array met variabele lengte van constante poolindexen die de interfaces beschrijven die door deze klasse worden geïmplementeerd
18+cpsize+isize 2 bytes u2 veldtelling, aantal ingangen in de volgende veldentabel
19+cpsize+isize
20+cpsize+isize fsize (variabel) table veldentabel, array van velden met variabele lengte

elk element is een field_info-structuur gedefinieerd 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, aantal items in de volgende methodetabel
21+cpsize+isize+fsize
22+cpsize+isize+fsize msize (variabel) table methodetabel, array van methodes met variabele lengte

elk element is een method_info-structuur gedefinieerd in https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.6

22+cpsize+isize+fsize+msize 2 bytes u2 attribuutaantal, aantal items in de volgende attribuuttabel
23+cpsize+isize+fsize+msize
24+cpsize+isize+fsize+msize asize (variabel) table attribuuttabel, matrix van attributen met variabele lengte

elk element is een attribuut_infostructuur gedefinieerd in https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.7

Voorstelling in een C-achtige programmeertaalEdit

Omdat C geen arrays met meerdere variabele lengtes binnen een struct ondersteunt, zal de onderstaande code niet compileren en dient deze slechts als demonstratie.

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;}

De constante poolEdit

De constante pool tabel is waar de meeste letterlijke constante waarden worden opgeslagen. Dit omvat waarden zoals getallen van alle soorten, strings, identifier namen, verwijzingen naar klassen en methoden, en type descriptors. Alle indexen, of verwijzingen, naar specifieke constanten in de constante pool tabel worden gegeven door 16-bits (type u2) getallen, waarbij index waarde 1 verwijst naar de eerste constante in de tabel (index waarde 0 is ongeldig).

Door historische keuzes gemaakt tijdens de ontwikkeling van het bestandsformaat, is het aantal constanten in de constante pool tabel in werkelijkheid niet hetzelfde als de constante pool telling die aan de tabel voorafgaat. Ten eerste is de tabel geïndexeerd beginnend bij 1 (in plaats van 0), maar de telling moet eigenlijk worden geïnterpreteerd als de maximum index plus één. Bovendien, twee soorten constanten (longs en doubles) nemen twee opeenvolgende slots in de tabel, hoewel de tweede zo’n slot een phantom index is die nooit direct wordt gebruikt.

Het type van elk item (constante) in de constante pool wordt geïdentificeerd door een initiële byte tag. Het aantal bytes na deze tag en hun interpretatie zijn dan afhankelijk van de tag waarde. De geldige constante types en hun tag waarden zijn:

Tag byte Aanvullende bytes Beschrijving van constante Versie geïntroduceerd
1 2+x bytes
(variabele)
UTF-8 (Unicode) string: een tekenreeks voorafgegaan door een 16-bits getal (type u2) dat het aantal bytes aangeeft in de gecodeerde tekenreeks die onmiddellijk volgt (en dat verschillend kan zijn van het aantal tekens). Merk op dat de gebruikte codering eigenlijk geen UTF-8 is, maar een lichte wijziging van de Unicode-standaardcoderingsvorm. 1.0.2
3 4 bytes Integer: een 32-bits two’s complement getal in big-endian formaat 1.0.2
4 4 bytes Float: een 32-bits single-precision IEEE 754 floating-point getal 1.0.2
5 8 bytes Long: een ondertekend 64-bit two’s complement getal in big-endian formaat (neemt twee slots in de constant pool tabel in) 1.0.2
6 8 bytes Double: een 64-bit double-precision IEEE 754 floating-point getal (neemt twee slots in de tabel met constante pool) 1.0.2
7 2 bytes Class reference: een index binnen de constant pool naar een UTF-8 string die de volledig gekwalificeerde class name bevat (in intern formaat) (big-endian) 1.0.2
8 2 bytes String reference: een index binnen de constante pool naar een UTF-8 string (ook big-endian) 1.0.2
9 4 bytes Field reference: twee indexen binnen de constant pool, de eerste die naar een Class reference wijst, de tweede naar een Name and Type descriptor. (big-endian) 1.0.2
10 4 bytes Methodeverwijzing: twee indexen binnen de constante pool, de eerste die wijst naar een Klasse-verwijzing, de tweede naar een Naam- en Type-descriptor. (big-endian) 1.0.2
11 4 bytes Interface method reference: twee indexen binnen de constante pool, de eerste die wijst naar een Klasse-verwijzing, de tweede naar een Name en Type descriptor. (big-endian) 1.0.2
12 4 bytes Naam- en type-descriptor: twee indexen naar UTF-8-strings binnen de constante pool, de eerste die een naam (identifier) weergeeft, de tweede een speciaal gecodeerde type-descriptor. 1.0.2
15 3 bytes Method handle: deze structuur wordt gebruikt om een method handle weer te geven en bestaat uit één byte van de type-descriptor, gevolgd door een index binnen de constante pool. 7
16 2 bytes Method type: deze structuur wordt gebruikt om een methodetype weer te geven, en bestaat uit een index binnen de constante pool. 7
17 4 bytes Dynamisch: deze wordt gebruikt om een dynamisch berekende constante op te geven die wordt geproduceerd door aanroeping van een bootstrap-methode. 11
18 4 bytes InvokeDynamic: dit wordt gebruikt door een invokedynamic-instructie om een bootstrap-methode te specificeren, de dynamische invocatienaam, de argument- en return-typen van de aanroep, en optioneel, een reeks aanvullende constanten die statische argumenten voor de bootstrap-methode worden genoemd. 7
19 2 bytes Module: dit wordt gebruikt om een module te identificeren. 9
20 2 bytes Package: dit wordt gebruikt om een pakket aan te duiden dat door een module wordt geëxporteerd of geopend. 9

Er zijn slechts twee integrale constante types, integer en long. Andere integrale typen die in de hogere taal voorkomen, zoals boolean, byte en short, moeten worden weergegeven als een integer constante.

Klassenamen in Java worden, wanneer ze volledig gekwalificeerd zijn, traditioneel door punten gescheiden, zoals “java.lang.Object”. Maar binnen de klasse-referentieconstanten op laag niveau, verschijnt een interne vorm die in plaats daarvan schuine strepen gebruikt, zoals “java/lang/Object”.

De Unicode strings, ondanks de bijnaam “UTF-8 string”, zijn in feite niet gecodeerd volgens de Unicode standaard, hoewel het er wel op lijkt. Er zijn twee verschillen (zie UTF-8 voor een volledige discussie). Het eerste is dat het codepunt U+0000 wordt gecodeerd als de twee-byte sequentie C0 80 (in hex) in plaats van de standaard enkel-byte codering 00. Het tweede verschil is dat aanvullende tekens (die buiten de BMP op U+10000 en hoger) worden gecodeerd met behulp van een surrogaat-paar constructie vergelijkbaar met UTF-16 in plaats van direct te worden gecodeerd met UTF-8. In dit geval wordt elk van de twee surrogaten apart gecodeerd in UTF-8. Bijvoorbeeld, U+1D11E wordt gecodeerd als de 6-byte sequentie ED A0 B4 ED B4 9E, in plaats van de correcte 4-byte UTF-8 codering van F0 9D 84 9E.

Geef een antwoord

Het e-mailadres wordt niet gepubliceerd.