SekcjeEdit
W strukturze pliku klasy Java występuje 10 podstawowych sekcji:
- Magic Number: 0xCAFEBABE
- Version of Class File Format: wersje minor i major pliku klasy
- Constant Pool: Pula stałych dla klasy
- Flagi dostępu: na przykład czy klasa jest abstrakcyjna, statyczna, itp.
- Ta klasa: Nazwa bieżącej klasy
- Super Class: Nazwa klasy nadrzędnej
- Interfejsy: Dowolne interfejsy w klasie
- Pola: Dowolne pola w klasie
- Metody: Dowolne metody w klasie
- Atrybuty: Wszelkie atrybuty klasy (na przykład nazwa pliku źródłowego itp.)
Magic NumberEdit
Pliki klas są identyfikowane przez następujący 4-bajtowy nagłówek (w systemie szesnastkowym): CA FE BA BE
(pierwsze 4 pozycje w poniższej tabeli). Historia tej magicznej liczby została wyjaśniona przez Jamesa Goslinga w odniesieniu do restauracji w Palo Alto:
„Kiedyś chodziliśmy na lunch do miejsca zwanego St Michael’s Alley. Według miejscowej legendy, w głębokiej mrocznej przeszłości, Grateful Dead występowali tam, zanim stali się sławni. To było całkiem zabawne miejsce, które było zdecydowanie Grateful Dead Kinda Place. Kiedy Jerry zmarł, postawili tam nawet małą buddyjską kapliczkę. Kiedy tam chodziliśmy, nazywaliśmy to miejsce Cafe Dead. Gdzieś po drodze zauważono, że jest to liczba HEX. Przerabiałem kod formatu plików i potrzebowałem kilku magicznych liczb: jednej dla pliku obiektów trwałych i jednej dla klas. Użyłem CAFEDEAD dla formatu pliku obiektu, a szukając 4 znakowych słów heksadecymalnych, które pasowały po „CAFE” (wydawało się, że to dobry temat), trafiłem na BABE i zdecydowałem się go użyć. Tak więc CAFEBABE stał się formatem plików klasowych, a CAFEDEAD formatem obiektów trwałych. Ale obiekt trwały odszedł, a wraz z nim odeszło użycie CAFEDEAD – ostatecznie został zastąpiony przez RMI.
Ogólny układEdit
Ponieważ plik klasy zawiera elementy o zmiennym rozmiarze i nie zawiera również wbudowanych offsetów pliku (lub wskaźników), jest zazwyczaj parsowany sekwencyjnie, od pierwszego bajtu w kierunku końca. Na najniższym poziomie format pliku jest opisany w kategoriach kilku podstawowych typów danych:
- u1: niepodpisana 8-bitowa liczba całkowita
- u2: niepodpisana 16-bitowa liczba całkowita w kolejności bajtów big-endian
- u4: niepodpisana 32-bitowa liczba całkowita w kolejności bajtów big-endian
- tablica: tablica elementów o zmiennej długości pewnego typu. Liczba elementów w tablicy jest identyfikowana przez poprzedzający numer count (count jest u2), ale rozmiar tablicy w bajtach może być określony tylko przez zbadanie każdego z jej elementów.
Niektóre z tych podstawowych typów są następnie reinterpretowane jako wartości wyższego poziomu (takie jak łańcuchy lub liczby zmiennoprzecinkowe), w zależności od kontekstu.Nie ma egzekwowania wyrównania słów, a więc nigdy nie są używane bajty wypełniające.Ogólny układ pliku klasy jest taki, jak pokazano w poniższej tabeli.
byte offset | size | type lub value | description |
---|---|---|---|
0 | 4 bajty | u1 = 0xCA hex |
magiczna liczba (CAFEBABE) używana do identyfikacji pliku jako zgodnego z formatem pliku klasy |
1 | u1 = 0xFE hex |
||
2 | u1 = 0xCA |
u1 = 0xBA hex |
|
3 | u1 = 0xBE hex |
||
4 | 2 bajty | u2 | podrzędny numer wersji formatu pliku klasy formatu pliku klasy, który jest używany |
5 | |||
6 | 2 bajty | u2 | numer głównej wersji formatu pliku klasy, który jest używany.
Java SE 17 = 61 (0x3D hex), |
7 | |||
8 | 2 bajty | u2 | constant pool count, liczba wpisów w następującej tabeli constant pool. Ta liczba jest co najmniej o jeden większa niż rzeczywista liczba wpisów; zobacz następującą dyskusję. |
9 | |||
10 | cpsize (zmienna) | tablica | constant pool table, tablica wpisów puli stałej o zmiennej wielkości, zawierająca elementy takie jak liczby literalne, łańcuchy i odwołania do klas lub metod. Indeksowana od 1, zawierająca (constant pool count – 1) liczbę wpisów w sumie (patrz uwaga). |
… | |||
… | |||
… | |||
10+cpsize | 2 bajty | u2 | flagi dostępu, bitmask |
11+cpsize | |||
12+cpsize | 2 bajty | u2 | identyfikuje tę klasę, indeks do stałej do wpisu typu „Class” |
13+cpsize | |||
14+cpsize | 2 bajty | u2 | identyfikuje super klasę, indeks do stałej puli do wpisu typu „Class” |
15+cpsize | |||
16+cpsize | 2 bajty | u2 | liczba interfejsów, liczba wpisów w następującej tabeli interfejsów |
17+cpsize | |||
18+cpsize | isize (zmienna) | tablica | interfejsów: tablica o zmiennej długości stałych indeksów puli opisujących interfejsy implementowane przez tę klasę |
… | |||
… | |||
… | |||
18+cpsize+isize | 2 bytes | u2 | field count, liczba wpisów w następującej tabeli pól |
19+cpsize+isize | |||
20+cpsize+isize | fsize (zmienna) | tablica | pole, tablica pól o zmiennej długości
każdy element jest strukturą field_info zdefiniowaną w https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.5 |
… | |||
… | |||
… | |||
20+cpsize+isize+fsize | 2 bajty | u2 | method count, liczba wpisów w następującej tabeli metod |
21+cpsize+isize+fsize | |||
22+cpsize+isize+fsize | msize (zmienna) | tablica | tablica metod, tablica metod o zmiennej długości
każdy element jest strukturą method_info zdefiniowaną w https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.6 |
… | |||
… | |||
… | |||
22+cpsize+isize+fsize+msize | 2 bajty | u2 | liczba atrybutów, liczba wpisów w następującej tabeli atrybutów |
23+cpsize+isize+fsize+msize | |||
24+cpsize+isize+fsize+msize | asize (zmienna) | tablica atrybutów, tablica atrybutów o zmiennej długości
każdy element jest strukturą attribute_info zdefiniowaną w https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.7 |
|
… | |||
… | |||
… |
Reprezentacja w języku programowania podobnym do CEdit
Ponieważ C nie obsługuje wielu tablic o zmiennej długości wewnątrz struct, poniższy kod nie skompiluje się i służy jedynie jako demonstracja.
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;}
Pula stałychEdit
Tablica stałych jest miejscem przechowywania większości dosłownych wartości stałych. Obejmuje to wartości takie jak wszelkiego rodzaju liczby, łańcuchy, nazwy identyfikatorów, odwołania do klas i metod oraz deskryptory typów. Wszystkie indeksy, lub odwołania, do konkretnych stałych w tabeli stałej puli są podane przez 16-bitowe (typ u2) liczby, gdzie wartość indeksu 1 odnosi się do pierwszej stałej w tabeli (wartość indeksu 0 jest nieważna).
Z powodu historycznych wyborów dokonanych podczas rozwoju formatu pliku, liczba stałych w tabeli stałej puli nie jest w rzeczywistości taka sama jak liczba stałych puli, która poprzedza tabelę. Po pierwsze, tabela jest indeksowana począwszy od 1 (a nie od 0), ale licznik powinien być interpretowany jako maksymalny indeks plus jeden. Dodatkowo, dwa typy stałych (longs i double) zajmują dwa kolejne sloty w tablicy, chociaż drugi taki slot jest indeksem fantomowym, który nigdy nie jest bezpośrednio używany.
Typ każdego elementu (stałej) w puli stałych jest identyfikowany przez początkowy znacznik bajtowy. Liczba bajtów następujących po tym znaczniku i ich interpretacja są następnie zależne od wartości znacznika. Poprawne typy stałych i ich wartości znaczników to:
Bajt znacznika | Dodatkowe bajty | Opis stałej | Wprowadzona wersja |
---|---|---|---|
1 | 2+x bajtów (zmienna) |
ŁańcuchUTF-8 (Unicode): łańcuch znaków poprzedzony 16-bitową liczbą (typ u2) wskazującą liczbę bajtów w zakodowanym łańcuchu, który bezpośrednio po nim następuje (która może być inna niż liczba znaków). Zauważ, że używane kodowanie nie jest w rzeczywistości UTF-8, ale obejmuje niewielką modyfikację standardowej formy kodowania Unicode. | 1.0.2 |
3 | 4 bajty | Integer: podpisana 32-bitowa liczba z uzupełnieniem dwójkowym w formacie big-endian | 1.0.2 |
4 | 4 bajty | Float: 32-bitowa liczba zmiennoprzecinkowa IEEE 754 o pojedynczej precyzji | 1.0.2 |
5 | 8 bajtów | Long: podpisana 64-bitowa liczba z uzupełnieniem dwójkowym w formacie big-endian (zajmuje dwa sloty w tabeli stałej puli) | 1.0.2 |
6 | 8 bajtów | Double: 64-bitowa liczba zmiennoprzecinkowa IEEE 754 o podwójnej precyzji (zajmuje dwa sloty w tabeli stałej puli) | 1.0.2 |
7 | 2 bajty | Odniesienie do klasy: indeks w ramach puli stałych do łańcucha UTF-8 zawierającego w pełni kwalifikowaną nazwę klasy (w formacie wewnętrznym) (big-endian) | 1.0.2 |
8 | 2 bajty | String reference: indeks w obrębie stałej do łańcucha UTF-8 (również big-endian) | 1.0.2 |
9 | 4 bajty | Odniesienie do pola: dwa indeksy wewnątrz stałej puli, pierwszy wskazujący na referencję do klasy, drugi do deskryptora nazwy i typu. (big-endian) | 1.0.2 |
10 | 4 bajty | Method reference: dwa indeksy w obrębie stałej puli, pierwszy wskazujący na odwołanie do klasy, drugi na deskryptor typu Name and Type. (big-endian) | 1.0.2 |
11 | 4 bajty | Odniesienie do metody interfejsu: dwa indeksy w ramach stałej puli, pierwszy wskazujący na odwołanie do klasy, drugi na deskryptor Nazwa i Typ. (big-endian) | 1.0.2 |
12 | 4 bajty | Nazwa i deskryptor typu: dwa indeksy do łańcuchów UTF-8 w obrębie stałej puli, pierwszy reprezentujący nazwę (identyfikator), drugi specjalnie zakodowany deskryptor typu. | 1.0.2 |
15 | 3 bajty | Uchwyt metody: ta struktura jest używana do reprezentowania uchwytu metody i składa się z jednego bajtu deskryptora typu, po którym następuje indeks w ramach puli stałych. | 7 |
16 | 2 bajty | Typ metody: ta struktura jest używana do reprezentowania typu metody i składa się z indeksu w ramach stałej puli. | 7 |
17 | 4 bajty | Dynamiczna: ta struktura jest używana do określenia dynamicznie obliczanej stałej produkowanej przez wywołanie metody bootstrap. | 11 |
18 | 4 bajty | InvokeDynamic: jest używane przez instrukcję invokedynamic do określenia metody bootstrap, nazwy dynamicznego wywołania, typów argumentu i powrotu wywołania oraz opcjonalnie sekwencji dodatkowych stałych zwanych statycznymi argumentami metody bootstrap. | 7 |
19 | 2 bajty | Moduł: służy do identyfikacji modułu. | 9 |
20 | 2 bajty | Pakiet: służy do identyfikacji pakietu eksportowanego lub otwieranego przez moduł. | 9 |
Istnieją tylko dwa stałe typy integralne, integer i long. Inne typy integralne występujące w języku wysokiego poziomu, takie jak boolean, byte i short muszą być reprezentowane jako stałe całkowite.
Nazwy klas w Javie, gdy są w pełni kwalifikowane, są tradycyjnie rozdzielane kropkami, takie jak „java.lang.Object”. Jednak w ramach niskopoziomowych stałych odniesienia do klasy, pojawia się wewnętrzna forma, która używa ukośników zamiast tego, takich jak „java/lang/Object”.
Lańcuchy Unicode, pomimo moniker „UTF-8 string”, nie są w rzeczywistości kodowane zgodnie ze standardem Unicode, chociaż jest to podobne. Istnieją dwie różnice (zobacz UTF-8 dla pełnej dyskusji). Pierwszą jest to, że punkt kodowy U+0000 jest zakodowany jako dwubajtowa sekwencja C0 80
(w heksach) zamiast standardowego jednobajtowego kodowania 00
. Druga różnica polega na tym, że znaki uzupełniające (te spoza BMP przy U+10000 i wyżej) są kodowane przy użyciu konstrukcji pary surogatów podobnej do UTF-16, a nie są bezpośrednio kodowane przy użyciu UTF-8. W tym przypadku każdy z dwóch surogatów jest kodowany oddzielnie w UTF-8. Na przykład, U+1D11E jest kodowany jako 6-bajtowa sekwencja ED A0 B4 ED B4 9E
, zamiast prawidłowego 4-bajtowego kodowania UTF-8 F0 9D 84 9E
.
.