- Ładowacz klas znajduje plik klasy i ładuje go do JVM, aby program mógł go użyć.
- Klasy są ładowane przy pierwszym użyciu, a nie podczas uruchamiania, a ładowacz lokalizuje bajtkod każdego razu.
- Wbudowane ładowacze tworzą łańcuch nadrzędny (bootstrap, platforma, aplikacja), który deleguje w górę.
- Dzięki niestandardowym ładowaczom mody Minecraft mogą poprawiać klasy gry podczas ich ładowania.
Ładowacz klas to część środowiska uruchomieniowego Java, która znajduje plik klasy i ładuje go do JVM, aby program mógł go użyć. Klasy nie są ładowane wszystkie na początku. JVM ładuje każdą z nich po raz pierwszy, gdy jest potrzebna, a ładowacz klas znajduje kod bajtowy, odczytuje go i przekazuje do JVM. Edycja Java Minecraft działa w oparciu o ten sam mechanizm.
Gdzie pasuje Opal
Opal to mod dla Fabric, a Fabric ładuje grę za pomocą własnego ładowacza klas, dzięki czemu mody mogą modyfikować klasy podczas ich ładowania. Przewodnik instalacji przeprowadza Cię przez proces instalacji.
Jak naprawdę działa ładowacz klas
Ładowacz klas przekształca nazwę klasy w używaną klasę w działającym JVM. Żądasz typu, ładowacz lokalizuje pasujące bajty .class, a JVM definiuje ten typ w pamięci.
Praca odbywa się w trzech krokach. Ładowacz znajduje bajtkod dla klasy o określonej nazwie. JVM weryfikuje i łączy go. Następnie klasa jest gotowa do użycia. Dlatego program Java może pobierać kod, o którym nie wspomniano podczas kompilacji: wystarczy nazwa, aby ładowacz mógł go znaleźć.
Hierarchia ładowaczy
Ładowacze klas są ułożone w hierarchię nadrzędną, a większość z nich najpierw pyta swojego nadrzędnego. Standardowa aplikacja ma trzy wbudowane ładowacze ułożone jeden na drugim.
| Ładowacz | Ładuje |
|---|---|
| Bootstrap | Rdzenne klasy środowiska uruchomieniowego Java |
| Platform | Standardowe moduły biblioteczne spoza rdzenia |
| Aplikacja | Własne klasy Twojego programu z classpath |
Gdy ładowacz aplikacji jest proszony o klasę, zazwyczaj najpierw deleguje zapytanie w górę. Nadrzędny ma szansę ją załadować, a dziecko próbuje tylko wtedy, gdy żaden nadrzędny nie może tego zrobić. Nazywa się to modelem delegacji i zapewnia spójność rdzennych typów w całym programie.
Tożsamość klasy i niestandardowe ładowacze
Klasa jest identyfikowana zarówno po nazwie, jak i loaderze, który ją zdefiniował. Dwa loadery mogą ładować klasy o tej samej nazwie, a JVM traktuje je jako dwa różne typy. Brzmi to jak drobiazg, ale to właśnie jest powód, dla którego loadery klas są tak potężne.
Programy mogą definiować własne loadery. Niestandardowy loader może odczytywać bytecode z dowolnego miejsca: z pliku jar, sieci, wygenerowanej tablicy bajtów, a nawet bytecode, który został przekształcony w trakcie ładowania. Dzięki temu działają systemy wtyczek, serwery aplikacji i frameworki modyfikacji, które ładują kod, o którym program hosta nie wiedział w czasie kompilacji.
Dlaczego to ma znaczenie dla modyfikacji Minecraft
Modifikacje istnieją dzięki niestandardowemu ładowaniu klas. Loader modów dla Minecrafta uruchamia grę za pomocą własnego loadera, aby móc przeglądać i modyfikować klasy gry w trakcie ładowania. To punkt zaczepienia, w którym odbywa się łatanie bytecode.
Kiedy loader znajduje się pomiędzy dyskiem a JVM, może przekształcić klasę tuż przed tym, jak JVM ją zdefiniuje. Mod może przepisać metodę gry, wstrzyknąć nowe zachowanie lub dodać pola, wszystko to bez zmodyfikowanej kopii gry na dysku. Klasa, którą ostatecznie uruchamia JVM, to ta poprawiona. Aby dowiedzieć się, jak to wpisuje się w szerszy obraz, zobacz Co to jest loader modów Minecraft?.
FAQ
Podczas pierwszego użycia, a nie podczas uruchamiania. Po raz pierwszy, gdy Twój kod dotknie typu, JVM prosi ładowacz klas o znalezienie i zdefiniowanie go. Nazywa się to leniwym ładowaniem.
Ładowacz prosi swojego rodzica o załadowanie klasy zanim spróbuje to zrobić sam. Łańcuch rodziców prowadzi aż do ładowacza bootstrap, który zapobiega dwukrotnemu ładowaniu podstawowych typów Java pod tą samą nazwą.
Tak, jeśli definiują je różne ładowacze klas. JVM identyfikuje klasę po jej nazwie oraz ładowaczu, który ją definiuje, więc klasy o tej samej nazwie z oddzielnych ładowaczy są typami odrębnymi.
Aby móc obserwować ładowanie klas gry i modyfikować je w pamięci. Niestandardowy ładowacz może przekształcać bytecode przed zdefiniowaniem klasy przez JVM, co pozwala modom zmieniać grę bez edycji plików na dysku.