Plik klasy Java - Java class file
Rodzaj mediów internetowych | aplikacja/java-vm, aplikacja/x-httpd-java |
---|---|
Opracowany przez | Mikrosystemy słoneczne |
Plik klasy Java to plik (z rozszerzeniem nazwy pliku .class ) zawierający kod bajtowy Java, który można wykonać w wirtualnej maszynie Java (JVM) . Plik klasy Java jest zwykle tworzony przez kompilator Java z plików źródłowych języka programowania Java ( plików .java ) zawierających klasy Java (alternatywnie do tworzenia plików klas można również użyć innych języków JVM ). Jeśli plik źródłowy ma więcej niż jedną klasę, każda klasa jest kompilowana w oddzielny plik klasy.
Maszyny JVM są dostępne dla wielu platform , a plik klasy skompilowany na jednej platformie będzie wykonywany na maszynie JVM innej platformy. Dzięki temu aplikacje Java są niezależne od platformy .
Historia
W dniu 11 grudnia 2006 r. format pliku klasy został zmodyfikowany w ramach żądania specyfikacji Java (JSR) 202.
Układ i struktura plików
Sekcje
Struktura plików klas Java składa się z 10 podstawowych sekcji:
- Magiczna liczba : 0xCAFEBABE
- Wersja formatu pliku klasy : podrzędna i główna wersja pliku klasy
- Stała pula : pula stałych dla klasy
- Access Flags : na przykład, czy klasa jest abstrakcyjna, statyczna itp.
- Ta klasa : nazwa obecnej klasy
- Super klasa : nazwa super klasy
- Interfejsy : dowolne interfejsy w klasie
- Pola : dowolne pola w klasie
- Metody : dowolne metody w klasie
- Atrybuty : dowolne atrybuty klasy (na przykład nazwa pliku źródłowego itp.)
Magiczny numer
Pliki klas są identyfikowane przez następujący 4- bajtowy nagłówek (w systemie szesnastkowym ): CA FE BA BE
(pierwsze 4 wpisy w tabeli poniżej). Historię tej magicznej liczby wyjaśnił James Gosling odnosząc się do restauracji w Palo Alto :
„Kiedyś chodziliśmy na lunch do miejsca o nazwie St Michael's Alley. Według lokalnej legendy, w głębokiej, mrocznej przeszłości występowali tam The Grateful Dead, zanim się rozwinęli. Dead Kinda Place. Kiedy zmarł Jerry , zbudowano nawet małą buddyjską świątynię. Kiedy tam chodziliśmy, nazywaliśmy to miejsce „Cafe Dead”. Gdzieś po drodze zauważono, że to numer HEX. Ja przerabiałem jakiś kod formatu pliku i potrzebowałem kilku magicznych liczb : jednej dla trwałego pliku obiektowego i jednej dla klas.Użyłem CAFEDEAD dla formatu pliku obiektowego i podczas grepowania dla 4-znakowych słów szesnastkowych, które pasują po „CAFE (wydawało się, że to dobry motyw) Uderzyłem BABE i postanowiłem go użyć. W tamtym czasie nie wydawało się to szczególnie ważne ani przeznaczone do nigdzie poza śmietnikiem historii. Tak więc CAFEBABE stało się aktami klasowymi format, a CAFEDEAD był formatem obiektu trwałego, ale funkcja obiektu trwałego przestała działać a wraz z nim poszło użycie CAFEDEAD - ostatecznie został on zastąpiony przez RMI .
Ogólny układ
Ponieważ plik klasy zawiera elementy o zmiennej wielkości i nie zawiera również osadzonych przesunięć plików (lub wskaźników), jest zwykle analizowany sekwencyjnie, od pierwszego bajtu do końca. Na najniższym poziomie format pliku opisany jest za pomocą kilku podstawowych typów danych:
- u1 : 8-bitowa liczba całkowita bez znaku
- u2 : 16-bitowa liczba całkowita bez znaku w kolejności bajtów big-endian
- u4 : 32-bitowa liczba całkowita bez znaku w kolejności bajtów big-endian
- table : tablica elementów o zmiennej długości pewnego typu. Liczba elementów w tabeli jest identyfikowana przez poprzedzający numer licznika (liczba to u2), ale rozmiar w bajtach tabeli można określić tylko poprzez zbadanie każdego z jej elementów.
Niektóre z tych podstawowych typów są następnie ponownie interpretowane jako wartości wyższego poziomu (takie jak ciągi lub liczby zmiennoprzecinkowe), w zależności od kontekstu. Nie ma wymuszania wyrównania słów, więc nigdy nie używa się bajtów dopełniających. Ogólny układ pliku klasy jest przedstawiony w poniższej tabeli.
przesunięcie bajtów | rozmiar | typ lub wartość | opis |
---|---|---|---|
0 | 4 bajty | u1 = 0xCA szesnastkowy |
magiczny numer (CAFEBABE) używany do identyfikacji pliku jako zgodnego z formatem pliku klasy |
1 | u1 = 0xFE szesnastkowy |
||
2 | u1 = 0xBA szesnastkowy |
||
3 | u1 = 0xBE hex |
||
4 | 2 bajty | u2 | podrzędny numer wersji używanego formatu pliku klasy |
5 | |||
6 | 2 bajty | u2 | główny numer wersji używanego formatu pliku klasy. Java SE 17 = 61 (0x3D hex), |
7 | |||
8 | 2 bajty | u2 | liczba stałych puli, liczba wpisów w następującej tabeli puli stałej. Ta liczba jest co najmniej o jeden większa niż rzeczywista liczba wpisów; patrz następująca dyskusja. |
9 | |||
10 | rozmiar cp (zmienny) | Tabela | tabela puli stałych, tablica wpisów puli stałych o zmiennej wielkości, zawierająca takie elementy, jak liczby dosłowne, łańcuchy i odwołania do klas lub metod. Indeksowane począwszy od 1, zawierające ( stała liczba puli - 1) łączna liczba wpisów (patrz uwaga). |
... | |||
... | |||
... | |||
10+ rozmiar cps | 2 bajty | u2 | flagi dostępu, maska bitowa |
11+ rozmiar cps | |||
12+ rozmiar cps | 2 bajty | u2 | identyfikuje tę klasę, indeksuje do puli stałej do wpisu typu „Klasa” |
13+ rozmiar cps | |||
14+ rozmiar cps | 2 bajty | u2 | identyfikuje superklasę , indeks do puli stałej do wpisu typu „Klasa” |
15+ rozmiar cps | |||
16+ rozmiar cps | 2 bajty | u2 | liczba interfejsów, liczba wpisów w poniższej tabeli interfejsów |
17+ rozmiar cps | |||
18+ rozmiar cps | irozmiar (zmienny) | Tabela | tablica interfejsów: tablica o zmiennej długości stałych indeksów puli opisująca interfejsy zaimplementowane przez tę klasę |
... | |||
... | |||
... | |||
18+ rozmiar cp + isize | 2 bajty | u2 | liczba pól, liczba wpisów w poniższej tabeli pól |
19+ rozmiar cp + isize | |||
20+ rozmiar cp + isize | frozmiar (zmienna) | Tabela | tabela pól, 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+ rozmiar cp + isize + fsize | 2 bajty | u2 | liczba metod, liczba wpisów w poniższej tabeli metod |
21+ rozmiar cp + isize + fsize | |||
22+ rozmiar cp + isize + fsize | mrozmiar (zmienny) | Tabela | tabela 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 poniższej tabeli atrybutów |
23+ rozmiar cp + isize + frozmiar + mrozmiar | |||
24+ cpsize + isize + fsize + msize | rozmiar (zmienny) | Tabela | 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 C
Ponieważ C nie obsługuje wielu tablic o zmiennej długości w strukturze, poniższy kod nie zostanie skompilowany i służy tylko jako demonstracja.
struct Class_File_Format {
u4 magic_number;
u2 minor_version;
u2 major_version;
u2 constant_pool_count;
cp_info constant_pool[constant_pool_count - 1];
u2 access_flags;
u2 this_class;
u2 super_class;
u2 interfaces_count;
u2 interfaces[interfaces_count];
u2 fields_count;
field_info fields[fields_count];
u2 methods_count;
method_info methods[methods_count];
u2 attributes_count;
attribute_info attributes[attributes_count];
}
Stała pula
Tabela puli stałych to miejsce, w którym przechowywana jest większość wartości stałych dosłownych. Obejmuje to wartości, takie jak liczby wszelkiego rodzaju, łańcuchy, nazwy identyfikatorów, odwołania do klas i metod oraz deskryptory typów. Wszystkie indeksy lub odwołania do określonych stałych w tabeli puli stałych są podane przez liczby 16-bitowe (typ u2), gdzie wartość indeksu 1 odnosi się do pierwszej stałej w tabeli (wartość indeksu 0 jest nieprawidłowa).
Z powodu historycznych wyborów dokonanych podczas opracowywania formatu pliku, liczba stałych w tabeli puli stałej nie jest w rzeczywistości taka sama jak liczba stałych puli poprzedzających tabelę. Po pierwsze, tabela jest indeksowana od 1 (a nie od 0), ale w rzeczywistości liczba powinna być interpretowana jako maksymalny indeks plus jeden. Dodatkowo dwa rodzaje stałych (longs i doubles) zajmują dwa kolejne miejsca w tabeli, chociaż drugi taki slot jest indeksem fantomowym, który nigdy nie jest bezpośrednio używany.
Typ każdej pozycji (stałej) w puli stałej jest identyfikowany przez początkowy znacznik bajtu . Liczba bajtów następujących po tym znaczniku i ich interpretacja zależą od wartości znacznika. Prawidłowe typy stałych i ich wartości znaczników to:
Bajt tagu | Dodatkowe bajty | Opis stałej | Wprowadzona wersja |
---|---|---|---|
1 | 2+ x bajtów (zmienna) |
Ciąg znaków UTF-8 (Unicode): ciąg znaków poprzedzony 16-bitową liczbą (typ u2) wskazującą liczbę bajtów w zakodowanym ciągu, który następuje bezpośrednio (która może być inna niż liczba znaków). Należy zauważyć, że użyte kodowanie nie jest w rzeczywistości UTF-8 , ale obejmuje niewielką modyfikację standardowego formatu kodowania Unicode. | 1.0.2 |
3 | 4 bajty | Liczba całkowita: podpisana 32-bitowa liczba uzupełniająca do dwójki 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 uzupełnień do dwójek w formacie big-endian (zajmuje dwa miejsca 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 miejsca w tabeli puli stałych) | 1.0.2 |
7 | 2 bajty | Odwołanie do klasy: indeks w puli stałej do ciągu znaków UTF-8 zawierającego w pełni kwalifikowaną nazwę klasy (w formacie wewnętrznym ) (big-endian) | 1.0.2 |
8 | 2 bajty | Odwołanie do łańcucha: indeks w puli stałej do łańcucha UTF-8 (również big-endian) | 1.0.2 |
9 | 4 bajty | Odwołanie do pola: dwa indeksy w puli stałej, pierwszy wskazuje na odwołanie do klasy, drugi na deskryptor nazwy i typu. (big-endian) | 1.0.2 |
10 | 4 bajty | Odwołanie do metody: dwa indeksy w puli stałej, pierwszy wskazuje na odwołanie do klasy, drugi na deskryptor nazwy i typu. (big-endian) | 1.0.2 |
11 | 4 bajty | Odniesienie do metody interfejsu: dwa indeksy w puli stałych, pierwszy wskazuje na odwołanie do klasy, drugi na deskryptor nazwy i typu. (big-endian) | 1.0.2 |
12 | 4 bajty | Deskryptor nazwy i typu: dwa indeksy do ciągów znaków UTF-8 w puli stałej, pierwszy reprezentujący nazwę (identyfikator), a 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 puli stałej. | 7 |
16 | 2 bajty | Typ metody: ta struktura służy do reprezentowania typu metody i składa się z indeksu w puli stałej. | 7 |
17 | 4 bajty | Dynamic: jest używany do określenia dynamicznie obliczanej stałej wytwarzanej przez wywołanie metody ładowania początkowego. | 11 |
18 | 4 bajty | InvokeDynamic: jest używany przez instrukcję invokedynamic do określenia metody ładowania początkowego, nazwy dynamicznego wywołania, argumentów i typów zwracanych wywołania oraz opcjonalnie sekwencji dodatkowych stałych zwanych argumentami statycznymi metody ładowania początkowego. | 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 typy stałych całkowitych, całkowite i długie. Inne typy całkowite występujące w języku wysokiego poziomu, takie jak boolean, byte i short, muszą być reprezentowane jako stała całkowita.
Nazwy klas w Javie, jeśli są w pełni kwalifikowane, są tradycyjnie rozdzielane kropkami, na przykład „java.lang.Object”. Jednak w obrębie stałych referencyjnych klasy niskiego poziomu pojawia się formularz wewnętrzny, który zamiast tego używa ukośników, na przykład „java/język/obiekt”.
Ciągi znaków Unicode, pomimo pseudonimu „ciąg UTF-8”, nie są w rzeczywistości zakodowane zgodnie ze standardem Unicode, chociaż jest podobny. Istnieją dwie różnice ( pełną dyskusję można znaleźć w UTF-8 ). Po pierwsze, punkt kodowy U+0000 jest zakodowany jako sekwencja dwubajtowa C0 80
(w szesnastce) zamiast standardowego kodowania jednobajtowego 00
. Druga różnica polega na tym, że znaki uzupełniające (te poza BMP na poziomie U+10000 i wyższym) są kodowane przy użyciu konstrukcji pary zastępczej podobnej do UTF-16, a nie bezpośrednio przy użyciu UTF-8. W tym przypadku każdy z dwóch surogatów jest zakodowany oddzielnie w UTF-8. Na przykład U+1D11E jest zakodowany jako 6-bajtowa sekwencja ED A0 B4 ED B4 9E
zamiast poprawnego 4-bajtowego kodowania UTF-8 w F0 9D 84 9E
.
Zobacz też
Bibliografia
Dalsza lektura
- Tim Lindholm , Frank Yellin (1999). Specyfikacja wirtualnej maszyny Java (wyd. drugie). Sala Prezydencka. Numer ISBN 0-201-43294-3. Źródło 2008-10-13 .Oficjalny dokument definiujący wirtualną maszynę Java , który zawiera format pliku klasy. Zarówno pierwsze, jak i drugie wydanie książki są bezpłatnie dostępne online do przeglądania i/lub pobierania .