OsiotMuokkaa
Java-luokkatiedoston rakenteessa on 10 perusosiota:
- Taikanumero: 0xCAFEBABE
- Luokkatiedoston formaatin versio: luokkatiedoston minor- ja major-versiot
- Konstanttipooli: Pool of constants for the class
- Access Flags: esimerkiksi onko luokka abstrakti, staattinen jne.
- This Class: Nykyisen luokan nimi
- Super Class: Super-luokan nimi
- Rajapinnat: Luokan mahdolliset rajapinnat
- Kentät: Kaikki luokan kentät
- Metodit: Kaikki luokan metodit
- Attribuutit: Luokan mahdolliset attribuutit (esim. lähdetiedoston nimi jne.)
Magic NumberEdit
Luokkatiedostot tunnistetaan seuraavalla 4 tavun otsikolla (heksadesimaalisessa muodossa): CA FE BA BE
(neljä ensimmäistä merkintää alla olevassa taulukossa). Tämän maagisen numeron historian selitti James Gosling viitaten ravintolaan Palo Altossa:
”Meillä oli tapana käydä lounaalla paikassa nimeltä St Michael’s Alley. Paikallisen legendan mukaan syvällä pimeässä menneisyydessä Grateful Dead esiintyi siellä ennen kuin se nousi suureksi. Se oli aika funky paikka, joka oli ehdottomasti Grateful Dead Kinda Place. Kun Jerry kuoli, sinne pystytettiin jopa pieni buddhalainen pyhäkkö. Kun kävimme siellä, kutsuimme paikkaa Cafe Deadiksi. Jossain vaiheessa huomattiin, että kyseessä oli HEX-numero. Olin uudistamassa tiedostomuotokoodia ja tarvitsin pari taikanumeroa: yhden pysyvää objektitiedostoa varten ja yhden luokkia varten. Käytin CAFEDEADia objektitiedoston muotoa varten, ja etsiessäni 4-merkkisiä heksasanoja, jotka sopivat ”CAFE”:n jälkeen (se tuntui olevan hyvä teema), törmäsin BABEen ja päätin käyttää sitä. tuolloin se ei tuntunut kauhean tärkeältä eikä sen kohtalona ollut mennä minnekään muualle kuin historian roskakoriin. Niinpä CAFEBABEsta tuli luokkatiedostomuoto ja CAFEDEADista pysyvien objektien muoto. Mutta pysyvien objektien mahdollisuus hävisi, ja sen mukana hävisi myös CAFEDEADin käyttö – se korvattiin lopulta RMI:llä.
Yleinen ulkoasuEdit
Koska luokkatiedosto sisältää vaihtelevan kokoisia kohteita eikä se sisällä myös upotettuja tiedostooffsetteja (tai osoittimia), se jäsennetään tyypillisesti peräkkäin, ensimmäisestä tavusta kohti loppua. Alimmalla tasolla tiedostomuoto kuvataan muutaman perustavanlaatuisen tietotyypin avulla:
- u1: 8-bittinen ennenmerkitsematon kokonaisluku
- u2: 16-bittinen ennenmerkitsematon kokonaisluku big-endiaanisessa tavujärjestyksessä
- u4: 32-bittinen ennenmerkitsematon kokonaisluku big-endiaanisessa tavujärjestyksessä
- taulukko (table): Joukko (array) vaihtelevan pituisia elementtejä jostakin tyypistä. Taulukon kohteiden lukumäärä tunnistetaan sitä edeltävällä laskentanumerolla (laskentanumero on u2), mutta taulukon koko tavuina voidaan määrittää vain tarkastelemalla kutakin sen kohdetta.
Joitakin näistä perustyypeistä tulkitaan sitten uudelleen korkeamman tason arvoiksi (kuten merkkijonoiksi tai liukuluvuiksi) asiayhteydestä riippuen.Sanakohdistusta (word alignment) ei pakoteta noudattamaan, joten pehmustustavaroita ei käytetä.Luokkatiedoston yleinen ulkoasu on seuraavassa taulukossa esitetyn mukainen.
tavun siirto | koko | tyyppi tai arvo | kuvaus |
---|---|---|---|
0 | 4 tavua | u1 = 0xCA hex |
maaginen numero (CAFEBABE), jolla tiedosto tunnistetaan luokkatiedostomuodon mukaiseksi |
1 | u1 = 0xFE hex |
||
2 | u1 = 0xBA hex |
||
3 | u1 = 0xBE hex |
||
4 | 2 tavua | u2 | miinusversioluku käytettävä luokkatiedostomuoto |
5 | |||
6 | 2 tavua | u2 | käytettävän luokkatiedostomuodon pääversionumero.
Java SE 17 = 61 (0x3D hex), |
7 | |||
8 | 2 tavua | u2 | konstanttipoolien lukumäärän määrä, merkintöjen määrä seuraavassa vakiopoolien taulukossa. Tämä luku on vähintään yhden verran suurempi kuin merkintöjen todellinen määrä; ks. seuraava keskustelu. |
9 | |||
10 | cpsize (muuttuja) | taulukko | constant pool -taulukko, vaihtelevan kokoisten constant pool -merkintöjen matriisi, joka sisältää elementtejä, kuten literaalisia numeroita, merkkijonoja ja viittauksia luokkiin tai menetelmiin. Indeksoitu alkaen 1:stä, sisältää (constant pool count – 1) merkintöjen kokonaismäärän (katso huomautus). |
… | |||
… | |||
… | |||
10+cpsize | 2 tavua | u2 | access flags, bittimerkki |
11+cpsize | |||
12+cpsize | 2 tavua | u2 | identifioi tämän luokan, indeksi vakioaltaan ”Class”-tyyppiseen merkintään |
13+cpsize | |||
14+cpsize | 2 tavua | u2 | identifioi superluokan, indeksi vakioaltaan ”Class”-tyyppiseen merkintään |
15+cpsize | |||
16+cpsize | 2 tavua | u2 | liitännän määrä, merkintöjen määrä seuraavassa rajapintataulussa |
17+cpsize | |||
18+cpsize | isize (muuttuja) | table | interface table: muuttujapituinen joukko vakiopooliindeksejä, jotka kuvaavat tämän luokan toteuttamia rajapintoja |
… | |||
… | |||
… | |||
18+cpsize+isize | 2 tavua | u2 | field count, merkintöjen lukumäärä seuraavassa kenttätaulukossa |
19+cpsize+isize | |||
20+cpsize+isize | fsize (muuttuja) | taulukko | kenttätaulukko, muuttujan pituinen kenttien joukko
jokainen elementti on kohdassa https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.5 |
määritelty field_info -rakenne… | |||
… | |||
… | |||
20+cpsize+isize+fsize | 2 tavua | u2 | method count, merkintöjen lukumäärä seuraavassa metoditaulukossa |
21+cpsize+isize+fsize | |||
22+cpsize+isize+fsize | msize (muuttuja) | taulukko | metoditaulukko, muuttujan pituinen joukko metodeja
jokainen elementti on https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.6 |
:ssä määritelty method_info rakenne… | |||
… | |||
… | |||
22+cpsize+isize+fsize+msize | 2 tavua | u2 | attribuuttien määrä, merkintöjen määrä seuraavassa attribuuttitaulukossa |
23+cpsize+isize+fsize+msize | |||
24+cpsize+isize+fsize+msize | asize (muuttuja) | taulukko | attribuuttitaulukko, muuttujan pituinen attribuuttien joukko
jokainen elementti on attribute_info -rakenne, joka on määritelty kohdassa https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.7 |
… | |||
… | |||
… |
Esitys C:n kaltaisella ohjelmointikielelläMuokkaa
Sen vuoksi, että C ei tue useita muuttuvan pituisia matriiseja yhden structin sisällä, alla oleva koodi ei käänny, ja se toimii vain demonstraationa.
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;}
VakiopooliEdit
Vakiopooli-taulukkoon tallennetaan suurin osa literaalisista vakioarvoista. Siihen kuuluvat sellaiset arvot kuin kaikenlaiset numerot, merkkijonot, tunnistenimet, viittaukset luokkiin ja metodeihin sekä tyyppikuvaajat. Kaikki indeksit eli viittaukset tiettyihin vakioihin vakiopoolitaulukossa annetaan 16-bittisinä (tyyppi u2) numeroina, joissa indeksiarvo 1 viittaa taulukon ensimmäiseen vakioon (indeksiarvo 0 on mitätön).
Tiedostomuodon kehityksessä tehtyjen historiallisten valintojen vuoksi vakioiden määrä vakiopoolitaulukossa ei todellisuudessa ole sama kuin taulukon edessä oleva vakiopoolin määrä. Ensinnäkin taulukko on indeksoitu alkaen 1:stä (eikä 0:sta), mutta lukumäärää pitäisi itse asiassa tulkita enimmäisindeksiksi plus yksi. Lisäksi kaksi vakiotyyppiä (longit ja doublet) vievät taulukossa kaksi peräkkäistä paikkaa, vaikka toinen tällainen paikka on näennäisindeksi, jota ei koskaan suoraan käytetä.
Kunkin vakiopoolin kohteen (vakion) tyyppi tunnistetaan alkutunnisteen avulla. Tämän tunnisteen jälkeisten tavujen määrä ja niiden tulkinta riippuvat tunnisteen arvosta. Kelvolliset vakiotyypit ja niiden tag-arvot ovat:
Tag-tavu | Lisätavut | Vakion kuvaus | Version käyttöönotto | |
---|---|---|---|---|
1 | 2+x tavua (muuttuja) |
UTF-8-merkkijono | UTF-8-merkkijono: merkkijono, jonka etuliitteenä on 16-bittinen luku (tyyppi u2), joka ilmaisee välittömästi seuraavan koodatun merkkijonon tavujen lukumäärän (joka voi olla eri kuin merkkien lukumäärä). Huomaa, että käytetty koodaus ei ole varsinaisesti UTF-8, vaan kyseessä on Unicode-standardin koodausmuodon lievä muokkaus. | 1.0.2 |
3 | 4 tavua | Integer: merkkipitoinen 32-bittinen kaksikomplementtiluku big-endian-muodossa | 1.0.2 | |
4 | 4 tavua | Float: 32-bittinen yhden tarkkuuden IEEE 754 -liukuluku liukuluvulla | 1.0.2 | |
5 | 8 tavua | Long: Merkitty 64-bittinen kaksoiskomplementtiluku big-endian-muodossa (vie kaksi paikkaa vakiolukutaulukossa) | 1.0.2 | |
6 | 8 tavua | Double: 64-bittinen kaksoistarkkuuden IEEE 754 -liukuluku (vie kaksi paikkaa vakiopoolitaulukossa) | 1.0.2 | |
7 | 2 tavua | Luokkaviittaus: vakioaltaan sisällä oleva indeksi UTF-8-merkkijonoon, joka sisältää täysin määritellyn luokan nimen (sisäisessä muodossa) (big-endian) | 1.0.2 | |
8 | 2 tavua | String-viittaus: indeksi UTF-8-merkkijonoon (myös big-endian) | 1.0.2 | |
9 | 4 tavua | Kenttäviittaus: kaksi indeksiä vakiopoolin sisällä, joista ensimmäinen osoittaa luokkaviittaukseen ja toinen Name and Type -kuvaajaan. (big-endian) | 1.0.2 | |
10 | 4 tavua | Menetelmäviittaus: kaksi indeksiä vakiopoolin sisällä, joista ensimmäinen osoittaa luokkaviittaukseen, toinen Name and Type -kuvaajaan. (big-endian) | 1.0.2 | |
11 | 4 tavua | Liitännäismenetelmäviittaus: kaksi indeksiä vakiopoolin sisällä, joista ensimmäinen osoittaa luokkaviittaukseen, toinen Name and Type -kuvaajaan. (big-endian) | 1.0.2 | |
12 | 4 tavua | Nimi- ja tyyppikuvaaja: kaksi indeksiä vakioaltaan sisällä oleviin UTF-8-merkkijonoihin, joista ensimmäinen viittaa nimeen (tunnisteeseen) ja toinen erikoiskoodattuun tyyppikuvaajaan. | 1.0.2 | |
15 | 3 tavua | Metodin kahva: Tätä rakennetta käytetään metodin kahvan esittämiseen, ja se koostuu yhdestä tavusta tyypin kuvaajaa, jota seuraa indeksi vakioaltaan sisällä. | 7 | |
16 | 2 tavua | Metodin tyyppi: Tätä rakennetta käytetään metodin tyypin esittämiseen, ja se koostuu indeksistä vakioaltaan sisällä. | 7 | |
17 | 4 tavua | Dynaaminen: tätä käytetään määrittelemään dynaamisesti laskettu vakio, joka tuotetaan kutsumalla käynnistysmetodia. | 11 | |
18 | 4 tavua | InvokeDynamic: tätä käytetään invokedynamic-käskyssä määrittämään bootstrap-metodi, dynaamisen kutsun nimi, kutsun argumentti- ja paluutyypit sekä valinnaisesti bootstrap-metodin staattisiksi argumenteiksi kutsuttujen lisävakioiden sarja. | 7 | |
19 | 2 tavua | Moduuli: Tätä käytetään moduulin tunnistamiseen. | 9 | |
20 | 2 tavua | Paketti: tätä käytetään tunnistamaan moduulin viemä tai avaama paketti. | 9 |
On vain kaksi integraalista vakiotyyppiä, kokonaisluku ja pitkä. Muut korkean tason kielessä esiintyvät integraalityypit, kuten boolean, byte ja short, on esitettävä kokonaislukuvakioina.
Luokkien nimet Javassa, kun ne ovat täysin päteviä, ovat perinteisesti piste-erotettuja, kuten ”java.lang.Object”. Matalan tason luokkaviitevakioiden sisällä esiintyy kuitenkin sisäinen muoto, jossa käytetään sen sijaan vinoviivoja, kuten ”java/lang/Object”.
Unicode-merkkijonoja ei nimimerkistä ”UTF-8-merkkijono” huolimatta itse asiassa koodata Unicode-standardin mukaisesti, vaikka se onkin samankaltainen. Niissä on kaksi eroa (ks. UTF-8, jossa on kattava keskustelu). Ensimmäinen on se, että koodipiste U+0000 on koodattu kahden tavun sarjana C0 80
(heksadesimaalina) standardin yhden tavun koodauksen 00
sijasta. Toinen ero on se, että lisämerkit (BMP:n ulkopuolella olevat merkit U+10000:ssa ja sen yläpuolella) koodataan UTF-16:n kaltaisella korvaavalla parirakenteella sen sijaan, että ne koodattaisiin suoraan UTF-8:lla. Tällöin kumpikin kahdesta sijaismerkistä koodataan UTF-8:ssa erikseen. Esimerkiksi U+1D11E koodataan 6 tavun sarjana ED A0 B4 ED B4 9E
, eikä oikeana 4 tavun UTF-8-koodauksena F0 9D 84 9E
.
.