Plik klasy Java

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),
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).
Szczegóły dotyczące wcześniejszych numerów wersji można znaleźć w przypisie 1 w The JavaTM Virtual Machine Specification 2nd edition

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.

.

Dodaj komentarz

Twój adres e-mail nie zostanie opublikowany.