Fișier de clasă Java

SecțiuniEdit

Există 10 secțiuni de bază în structura fișierului de clasă Java:

  • Număr magic: 0xCAFEBABE
  • Versiunea formatului fișierului de clasă: versiunile minore și majore ale fișierului de clasă
  • Constant Pool: Pool of constants for the class
  • Access Flags: de exemplu, dacă clasa este abstractă, statică etc.
  • This Class: Numele clasei curente
  • Superclasa: Numele superclasei
  • Interfețe: Orice interfețe din clasă
  • Fields: Orice câmpuri din clasă
  • Metode: Orice metode din clasă
  • Atribute: Orice atribute ale clasei (de exemplu, numele fișierului sursă etc.)

Magic NumberEdit

Arhivele de clasă se identifică prin următorul antet de 4 octeți (în hexazecimal): CA FE BA BE (primele 4 intrări din tabelul de mai jos). Istoria acestui număr magic a fost explicată de James Gosling referindu-se la un restaurant din Palo Alto:

„Obișnuiam să mergem să luăm prânzul la un loc numit St Michael’s Alley. Conform legendei locale, în trecutul profund și întunecat, cei de la Grateful Dead obișnuiau să cânte acolo înainte de a deveni mari. Era un loc destul de funky, care era cu siguranță un Grateful Dead Kinda Place. Când Jerry a murit, au ridicat chiar și un mic altar de tip budist. Când obișnuiam să mergem acolo, ne refeream la acest loc ca la Cafe Dead. Undeva, de-a lungul timpului, s-a observat că acesta era un număr HEX. Am refăcut un cod de format de fișier și aveam nevoie de câteva numere magice: unul pentru fișierul obiect persistent și unul pentru clase. Am folosit CAFEDEAD pentru formatul fișierului de obiecte și, căutând cuvinte hexagonale de 4 caractere care să se potrivească după „CAFE” (părea să fie o temă bună), am dat peste BABE și am decis să îl folosesc. în acel moment, nu părea teribil de important sau menit să ajungă altundeva decât la coșul de gunoi al istoriei. Astfel, CAFEBABE a devenit formatul fișierelor de clasă, iar CAFEDEAD a fost formatul de obiecte persistente. Dar facilitatea de obiecte persistente a dispărut și, odată cu ea, a dispărut și utilizarea CAFEDEAD – în cele din urmă a fost înlocuită de RMI.

General layoutEdit

Pentru că fișierul de clasă conține elemente de mărime variabilă și nu conține, de asemenea, offseturi de fișier încorporate (sau pointeri), acesta este analizat de obicei secvențial, de la primul octet spre sfârșit. La nivelul cel mai de jos, formatul fișierului este descris în termenii câtorva tipuri de date fundamentale:

  • u1: un număr întreg de 8 biți fără semn
  • u2: un număr întreg de 16 biți fără semn în ordine big-endian de octeți
  • u4: un număr întreg de 32 de biți fără semn în ordine big-endian de octeți
  • tabel: o matrice de elemente de lungime variabilă de un anumit tip. Numărul de elemente din tabel este identificat printr-un număr de numărare precedent (numărul este un u2), dar dimensiunea în octeți a tabelului poate fi determinată numai prin examinarea fiecăruia dintre elementele sale.

Câteva dintre aceste tipuri fundamentale sunt apoi reinterpretate ca valori de nivel superior (cum ar fi șiruri de caractere sau numere cu virgulă mobilă), în funcție de context.Nu se aplică alinierea cuvintelor și, prin urmare, nu se utilizează niciodată octeți de umplutură.Dispunerea generală a fișierului de clasă este cea prezentată în tabelul următor.

byte offset dimensiune tip sau valoare descriere
0 4 octeți u1 =
0xCA hex
număr magic (CAFEBABE) utilizat pentru a identifica fișierul ca fiind conform cu formatul fișierului de clasă
1 u1 =
0xFE hex
2 u1 =
0xBA hex
3 u1 =
0xBE hex
4 2 octeți u2 numărul versiunii minore a format de fișier de clasă utilizat
5
6 2 octeți u2 numărul versiunii principale a formatului de fișier de clasă utilizat.

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 hexazecimal),
JDK 1.4 = 48 (0x30 hexazecimal),
JDK 1.3 = 47 (0x2F hexazecimal),
JDK 1.2 = 46 (0x2E hexazecimal),
JDK 1.1 = 45 (0x2D hexazecimal).
Pentru detalii privind numerele versiunilor anterioare, a se vedea nota de subsol 1 la The JavaTM Virtual Machine Specification 2nd edition

7
8 2 octeți u2 constant pool count, numărul de intrări în următorul tabel constant pool. Acest număr este cu cel puțin unul mai mare decât numărul real de intrări; a se vedea discuția următoare.
9
10 cpsize (variabilă) table constant pool table, un tablou de intrări de dimensiuni variabile în constant pool, care conține elemente precum numere literale, șiruri de caractere și referințe la clase sau metode. Indexat începând de la 1, conținând (numărul de constante – 1) numărul total de intrări (a se vedea nota).
10+cpsize 2 octeți u2 simboluri de acces, o mască de biți
11+cpsize
12+cpsize 2 octeți u2 identifică această clasă, index în fondul de constante la o intrare de tip „Class”-tip
13+cpsize
14+cpsize 2 bytes u2 identifică superclasa, index în fondul de constante la o intrare de tip „Class”-tip
15+cpsize
16+cpsize 2 bytes u2 numărul de interfețe, numărul de intrări în următoarea tabelă de interfețe
17+cpsize
18+cpsize isize (variabilă) table tabel de interfețe: o matrice de lungime variabilă de indici de pool constant care descriu interfețele implementate de această clasă
18+cpsize+isize 2 octeți u2 număr de câmpuri, numărul de intrări în următorul tabel de câmpuri
19+cpsize+isize
20+cpsize+isize fsize (variabilă) table table de câmpuri, matrice de câmpuri de lungime variabilă

fiecare element este o structură field_info definită în https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.5

20+cpsize+isize+fsize 2 octeți u2 numărul metodei, numărul de intrări în următorul tabel de metode
21+cpsize+isize+fsize
22+cpsize+isize+fsize msize (variabilă) table Tabelă de metode, matrice de metode de lungime variabilă

fiecare element este o structură method_info definită în https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.6

22+cpsize+isize+fsize+msize 2 octeți u2 număr de atribute, numărul de intrări în următorul tabel de atribute
23+cpsize+isize+fsize+msize
24+cpsize+isize+fsize+msize asize (variabilă) table table de atribute, matrice de atribute de lungime variabilă

fiecare element este o structură attribute_info definită în https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.7

….

Reprezentare într-un limbaj de programare de tip CEdit

Din moment ce C nu suportă array-uri multiple de lungime variabilă în cadrul unei structuri, codul de mai jos nu va fi compilat și servește doar ca demonstrație.

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

Tabloul de constanteEdit

Tabloul de constante este locul unde sunt stocate majoritatea valorilor constantelor literale. Aceasta include valori precum numere de tot felul, șiruri de caractere, nume de identificatori, referințe la clase și metode și descriptori de tip. Toți indicii sau referințele la constantele specifice din tabelul constant pool sunt date de numere pe 16 biți (tip u2), unde valoarea indexului 1 se referă la prima constantă din tabel (valoarea indexului 0 nu este valabilă).

Din cauza unor alegeri istorice făcute în timpul dezvoltării formatului de fișier, numărul de constante din tabelul constant pool nu este de fapt același cu numărul de constante din tabelul constant pool care precede tabelul. În primul rând, tabelul este indexat începând de la 1 (și nu de la 0), dar numărătoarea ar trebui de fapt interpretată ca fiind indexul maxim plus unu. În plus, două tipuri de constante (long și double) ocupă două sloturi consecutive în tabel, deși cel de-al doilea astfel de slot este un index fantomă care nu este niciodată utilizat direct.

Tipul fiecărui element (constantă) din fondul de constante este identificat printr-o etichetă inițială de octet. Numărul de octeți care urmează după această etichetă și interpretarea lor depind apoi de valoarea etichetei. Tipurile de constante valide și valorile tag-urilor lor sunt::

Tag byte Biteți adiționali Descrierea constantei Versiunea introdusă
1 2+x bytes
(variabilă)
ȘirUTF-8 (Unicode): un șir de caractere prefixat de un număr de 16 biți (tip u2) care indică numărul de octeți din șirul codificat care urmează imediat (care poate fi diferit de numărul de caractere). Rețineți că codificarea utilizată nu este de fapt UTF-8, ci implică o ușoară modificare a formei de codificare standard Unicode. 1.0.2
3 4 octeți Integer: un număr semnat de 32 de biți cu complement pe doi în format big-endian 1.0.2
4 4 octeți Float: un număr în virgulă mobilă IEEE 754 de 32 de biți cu o singură precizie 1.0.2
5 8 octeți Long: un număr cu semn pe 64 de biți cu complement pe doi în format big-endian (ocupă două sloturi în tabelul de rezervă de constante) 1.0.2
6 8 octeți Double: un număr în virgulă mobilă IEEE 754 cu precizie dublă pe 64 de biți (ocupă două sloturi în tabelul de rezerve constante) 1.0.2
7 2 octeți Referință de clasă: un index în cadrul grupului de constante pentru un șir UTF-8 care conține numele complet calificat al clasei (în format intern) (big-endian) 1.0.2
8 2 octeți String reference: un index în cadrul grupului de constante către un șir UTF-8 (big-endian de asemenea) 1.0.2
9 4 octeți Referință de câmp: doi indici în cadrul grupului de constante, primul punctând spre o referință de clasă, al doilea spre un descriptor de nume și tip. (big-endian) 1.0.2
10 4 octeți Referință de metodă: doi indici în cadrul grupului de constante, primul indicând o referință de clasă, al doilea un descriptor de nume și tip. (big-endian) 1.0.2
11 4 octeți Referință la o metodă de interfață: doi indici în cadrul grupului de constante, primul indicând o referință de clasă, al doilea un descriptor de nume și tip. (big-endian) 1.0.2
12 4 octeți Descriptor de nume și tip: doi indici către șiruri UTF-8 din cadrul grupului de constante, primul reprezentând un nume (identificator), iar al doilea un descriptor de tip special codificat. 1.0.2
15 3 octeți Method handle: această structură este utilizată pentru a reprezenta un mâner de metodă și constă dintr-un octet de descriptor de tip, urmat de un index în cadrul grupului de constante. 7
16 2 octeți Tipul metodei: această structură este utilizată pentru a reprezenta un tip de metodă și constă într-un index în cadrul grupului de constante. 7
17 4 octeți Dinamic: această structură este utilizată pentru a specifica o constantă calculată dinamic, produsă prin invocarea unei metode bootstrap. 11
18 4 octeți InvokeDynamic: aceasta este utilizată de o instrucțiune invokedynamic pentru a specifica o metodă bootstrap, numele de invocare dinamică, tipul de argument și tipul de retur al apelului și, opțional, o secvență de constante suplimentare numite argumente statice ale metodei bootstrap. 7
19 2 octeți Module: se utilizează pentru a identifica un modul. 9
20 2 octeți Pachet: se utilizează pentru a identifica un pachet exportat sau deschis de un modul. 9

Există doar două tipuri de constante integrale, integer și long. Alte tipuri integrale care apar în limbajul de nivel înalt, cum ar fi boolean, byte și short trebuie să fie reprezentate ca o constantă de tip întreg.

Numele claselor în Java, atunci când sunt calificate complet, sunt în mod tradițional separate prin puncte, cum ar fi „java.lang.Object”. Cu toate acestea, în cadrul constantelor de referință de clasă de nivel inferior, apare o formă internă care folosește în schimb bară oblică, cum ar fi „java/lang/Object”.

Circuitele Unicode, în ciuda denumirii de „șir UTF-8”, nu sunt de fapt codificate conform standardului Unicode, deși este similar. Există două diferențe (a se vedea UTF-8 pentru o discuție completă). Prima este că punctul de cod U+0000 este codificat ca secvența de doi octeți C0 80 (în hexagonal) în loc de codificarea standard de un singur octet 00. A doua diferență constă în faptul că caracterele suplimentare (cele aflate în afara BMP la U+10000 și mai sus) sunt codificate folosind o construcție de perechi de surogate similară cu UTF-16, în loc să fie codificate direct folosind UTF-8. În acest caz, fiecare dintre cei doi surogate este codificat separat în UTF-8. De exemplu, U+1D11E este codificat ca secvența de 6 octeți ED A0 B4 ED B4 9E, în loc de codificarea UTF-8 corectă de 4 octeți F0 9D 84 9E.

.

Lasă un răspuns

Adresa ta de email nu va fi publicată.