Java osztályfájl

SzakaszokSzerkesztés

A Java osztályfájl szerkezetének 10 alapvető szakasza van:

  • Mágikus szám: 0xCAFEBABE
  • Az osztályfájl formátumának verziója: az osztályfájl kisebb és nagyobb verziója
  • Állandó állomány: Az osztály konstansainak tárháza
  • Access Flags: például, hogy az osztály absztrakt, statikus stb.
  • This Class: Az aktuális osztály neve
  • Super Class: A szuperosztály neve
  • Interfaces: Az osztályban lévő bármely interfész
  • Fields: Az osztályban található bármely mező
  • Módszerek: Bármely metódus az osztályban
  • Attribútumok: Az osztály bármely attribútuma (például a forrásfájl neve stb.)

Magic NumberEdit

Az osztályfájlokat a következő 4 bájtos fejléccel azonosítjuk (hexadecimálisan): CA FE BA BE (az alábbi táblázat első 4 bejegyzése). Ennek a bűvös számnak a történetét James Gosling egy Palo Alto-i étteremre utalva magyarázta el:

“Egy St Michael’s Alley nevű helyre jártunk ebédelni. A helyi legenda szerint a mély, sötét múltban a Grateful Dead lépett fel ott, mielőtt nagyot alkottak. Eléggé funky hely volt, ami határozottan egy Grateful Dead-féle hely volt. Amikor Jerry meghalt, még egy kis buddhista szentélyt is felállítottak. Amikor oda jártunk, Cafe Deadként emlegettük a helyet. Valamikor aztán észrevettük, hogy ez egy HEX szám. Átalakítottam néhány fájlformátum kódot, és szükségem volt néhány mágikus számra: egy a perzisztens objektumfájlhoz, és egy az osztályokhoz. A CAFEDEAD-et használtam az objektumfájl formátumhoz, és a “CAFE” után megfelelő 4 karakteres hexa szavak keresése közben (jó témának tűnt) rábukkantam a BABE-ra, és úgy döntöttem, hogy ezt fogom használni. akkoriban nem tűnt túl fontosnak, vagy arra szántam, hogy a történelem szemétkosarába kerüljön. Így lett a CAFEBABE az osztályfájl-formátum, a CAFEDEAD pedig a tartós objektumformátum. De a perzisztens objektum lehetőség eltűnt, és vele együtt eltűnt a CAFEDEAD használata is – végül az RMI váltotta fel.

Általános layoutEdit

Mivel az osztályfájl változó méretű elemeket tartalmaz, és nem tartalmaz beágyazott fájloffszetet (vagy mutatót) is, általában szekvenciálisan, az első bájttól a vége felé elemzik. A legalacsonyabb szinten a fájlformátum néhány alapvető adattípussal írható le:

  • u1: egy előjel nélküli 8 bites egész szám
  • u2: egy előjel nélküli 16 bites egész szám big-endian bájtsorrendben
  • u4: egy előjel nélküli 32 bites egész szám big-endian bájtsorrendben
  • táblázat: valamilyen típusú, változó hosszúságú elemek tömbje. A táblázatban lévő elemek számát az azt megelőző számlálószám azonosítja (a számlálószám egy u2), de a táblázat bájtokban kifejezett mérete csak az egyes elemek vizsgálatával határozható meg.

Ezek közül az alapvető típusok közül néhányat a kontextustól függően magasabb szintű értékként (például stringként vagy lebegőpontos számként) értelmezünk újra.Nincs szókiigazítás kényszerítése, ezért soha nem használunk töltőbájtokat.Az osztályfájl teljes elrendezése a következő táblázatban látható.

byte offset size type or value description
0 4 byte u1 =
0xCA hex
mágikus szám (CAFEBABE), amellyel a fájlt az osztályfájl formátumnak megfelelőként azonosítják
1 u1 =
0xFE hex
2 u1 =
0xBA hex
3 u1 =
0xBE hex
4 2 bájt u2 minor verziószám a használt osztályfájlformátum
5
6 2 bájt u2 a használt osztályfájlformátum fő verziószáma.

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).
A korábbi verziószámok részleteit lásd a The JavaTM Virtual Machine Specification 2nd edition 1. lábjegyzetében

7
8 2 byte u2 constant pool count, a következő constant pool táblázat bejegyzéseinek száma. Ez a szám legalább eggyel nagyobb, mint a bejegyzések tényleges száma; lásd a következő tárgyalást.
9
10 cpsize (változó) table constant pool table, változó méretű konstans pool bejegyzések tömbje, amely olyan elemeket tartalmaz, mint literális számok, karakterláncok, osztályokra vagy módszerekre való hivatkozások. Az 1-gyel kezdődően indexelt, összesen (konstanskészlet-szám – 1) számú bejegyzést tartalmaz (lásd a megjegyzést).
10+cpsize 2 byte u2 access flags, egy bitmaszk
11+cpsize
12+cpsize 2 byte u2 azonosítja ezt az osztályt, index a konstanskészletben egy “Class”-típusú bejegyzéshez
13+cpsize
14+cpsize 2 byte u2 azonosítja a szuperosztályt, index a konstans poolban egy “Class”-típusú bejegyzéshez
15+cpsize
16+cpsize 2 byte u2 interfész szám, a következő interfész táblában
17+cpsize
18+cpsize isize (változó) table interface table: Az osztály által megvalósított interfészeket leíró konstans pool indexek változó hosszúságú tömbje
18+cpsize+isize 2 byte u2 mezőszám, a következő mezőtábla bejegyzéseinek száma
19+cpsize+isize
20+cpsize+isize fsize (változó) table field table, változó hosszúságú mezőtömb

minden elem a https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.5

-ben definiált field_info struktúra…
20+cpsize+isize+fsize 2 byte u2 method count, a következő módszertáblában
21+cpsize+isize+fsize
22+cpsize+isize+fsize msize (változó) table method table, Módszerek változó hosszúságú tömbje

minden elem a https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.6

-ben definiált method_info struktúra…
22+cpsize+isize+fsize+msize 2 byte u2 attribute count, bejegyzések száma a következő attribútumtáblában
23+cpsize+isize+fsize+msize
24+cpsize+isize+fsize+msize asize (változó) table attribute table, változó hosszúságú attribútumtömb

minden elem egy https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.7

-ben definiált attribute_info struktúra…

C-szerű programozási nyelven való ábrázolásSzerkesztés

Mivel a C nem támogatja a többszörös változó hosszúságú tömböket egy struktúrán belül, az alábbi kód nem fordítható le, és csak demonstrációként szolgál.

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

A konstanskészletEdit

A konstanskészlet táblában tároljuk a legtöbb literális konstans értéket. Ide tartoznak az olyan értékek, mint a mindenféle számok, karakterláncok, azonosítónevek, osztályokra és metódusokra való hivatkozások, valamint típusleírók. A konstanskészlet-táblában az összes indexet, illetve a konkrét konstansokra való hivatkozást 16 bites (u2 típusú) számok adják meg, ahol az 1-es indexérték a táblázat első konstansára utal (a 0-s indexérték érvénytelen).

A fájlformátum fejlesztése során hozott történelmi döntések miatt a konstanskészlet-táblában lévő konstansok száma valójában nem azonos a táblázatot megelőző konstanskészlet számával. Először is, a táblázat indexelése 1-től kezdődik (és nem 0-tól), de a számot valójában a maximális index plusz egy indexként kell értelmezni. Továbbá, a konstansok két típusa (hosszúak és duplák) két egymást követő helyet foglal el a táblázatban, bár a második ilyen hely egy fantomindex, amelyet soha nem használunk közvetlenül.

A konstanskészletben lévő minden egyes elem (konstans) típusát egy kezdeti bájtcímke azonosítja. Az ezt követő bájtok száma és értelmezése a tag értékétől függ. Az érvényes konstans típusok és azok tag értékei a következők:

Tag bájt Kiegészítő bájtok A konstans leírása Bevezetett verzió
1 2+x bájt
(változó)
UTF-8 (Unicode) string: (u2 típusú) karakterlánc, amelynek előtagja egy 16 bites szám (u2 típusú), amely a közvetlenül utána következő kódolt karakterlánc bájtjainak számát jelzi (amely eltérhet a karakterek számától). Megjegyzendő, hogy az alkalmazott kódolás valójában nem UTF-8, hanem a Unicode szabványos kódolási forma enyhe módosítását jelenti. 1.0.2
3 4 bájt Integer: egy előjeles 32 bites kettes komplement szám big-endian formátumban 1.0.2
4 4 bájt Float: 32 bites, egyszeres pontosságú IEEE 754 lebegőpontos szám 1.0.2
5 8 bájt Long: egy előjeles 64 bites kétkomplementes szám big-endian formátumban (két helyet foglal el a konstanskészlet táblázatban) 1.0.2
6 8 bájt Double: 64 bites kétszeres pontosságú IEEE 754 lebegőpontos szám (két helyet foglal el a konstansok táblájában) 1.0.2
7 2 bájt Osztályhivatkozás: a konstanskészleten belüli index egy UTF-8 karakterlánchoz, amely a teljesen minősített osztály nevét tartalmazza (belső formátumban) (big-endian) 1.0.2
8 2 bájt String hivatkozás: a konstanskészleten belüli index egy UTF-8 karakterláncra (szintén big-endian) 1.0.2
9 4 bájt Mezőhivatkozás: két index a konstanskészleten belül, az első egy osztályhivatkozásra, a második egy név és típus leíróra mutat. (big-endian) 1.0.2
10 4 byte Módszerreferencia: két index a konstanskészleten belül, az első egy osztályreferenciára, a második egy név- és típusleíróra mutat. (big-endian) 1.0.2
11 4 byte Interface metódus hivatkozás: két index a konstanskészleten belül, az első egy Class hivatkozásra, a második egy Name and Type leíróra mutat. (big-endian) 1.0.2
12 4 bájt Név és típus leíró: két index a konstanskészleten belüli UTF-8 karakterláncokra, az első egy névre (azonosítóra), a második egy speciálisan kódolt típus leíróra mutat. 1.0.2
15 3 bájt Módszerkezelő: Ez a struktúra egy módszerkezelő ábrázolására szolgál, és egy bájt típusleíróból, majd a konstanskészleten belüli indexből áll. 7
16 2 bájt Módszertípus: Ez a struktúra egy módszertípus reprezentálására szolgál, és egy indexből áll a konstanskészleten belül. 7
17 4 bájt Dinamikus: ez egy bootstrap módszer meghívásával előállított dinamikusan kiszámított konstans megadására szolgál. 11
18 4 bájt InvokeDynamic: ezt egy invokedynamic utasítás használja egy bootstrap módszer, a dinamikus hívás nevének, a hívás argumentum- és visszatérési típusainak, valamint opcionálisan a bootstrap módszer statikus argumentumainak nevezett további konstansok sorozatának megadására. 7
19 2 bájt Modul: egy modul azonosítására szolgál. 9
20 2 bájt Package: egy modul által exportált vagy megnyitott csomag azonosítására szolgál. 9

Kizárólag két integrál konstans típus létezik, az integer és a long. A magas szintű nyelvben megjelenő egyéb integrál típusokat, mint például a boolean, a byte és a short, egész konstansként kell ábrázolni.

A Java-ban az osztálynevek, ha teljes minősítésűek, hagyományosan ponttal vannak elválasztva, például “java.lang.Object”. Az alacsony szintű osztályhivatkozási konstansokon belül azonban megjelenik egy olyan belső forma, amely ehelyett kötőjeleket használ, például “java/lang/Object”.

A Unicode karakterláncok az “UTF-8 string” elnevezés ellenére valójában nem a Unicode szabvány szerint vannak kódolva, bár hasonló. Két különbség van (lásd az UTF-8 teljes körű tárgyalását). Az első az, hogy az U+0000 kódpontot a szabványos egybájtos 00 kódolás helyett a kétbájtos C0 80 (hexában) kódolással kódolják. A második különbség az, hogy a kiegészítő karakterek (a BMP-n kívül eső karakterek az U+10000 és afelett) kódolása az UTF-16-hoz hasonló helyettesítőpáros konstrukcióval történik, ahelyett, hogy közvetlenül az UTF-8 kódolással történne. Ebben az esetben mindkét helyettesítő karaktert külön-külön kódoljuk az UTF-8-ban. Például az U+1D11E kódolása a 6 bájtos ED A0 B4 ED B4 9E szekvenciaként történik, ahelyett, hogy a helyes 4 bájtos UTF-8 kódolás F0 9D 84 9E.

lenne.

Vélemény, hozzászólás?

Az e-mail-címet nem tesszük közzé.