Learn · concepts
Java Sınıf Yükleyicisi Nedir?
Bir sınıf yükleyici, çalışma zamanında Java sınıflarını JVM'ye bulur ve yükler. İşte bunların nasıl çalıştığı, hiyerarşinin neden önemli olduğu ve modların bunlara neden bağlı olduğu.
Bir sınıf yükleyici, Java çalışma zamanının bir sınıf dosyasını bulan ve onu JVM'ye yükleyen kısmıdır. Kodunuz her defasında bir türle ilk kez etkileşime girdiğinde, JVM bir sınıf yükleyicisine sorar: "Bana bu sınıfı bul." Yükleyici, bayt kodunu bulur, okur ve JVM sınıfı bellekte tanımlar. Bu mekanizma normal Java programlarında görünmez, ancak mod çerçevelerinin Minecraft'ı yamalamak için kullandığı tam bağlantı noktasıdır.
Bir sınıf yükleyicisi aslında ne yapar
Bir sınıf yükleyici, bir sınıf adını çalışan JVM içindeki kullanılabilir bir sınıfa dönüştürür. Bir tür için talepte bulunursunuz, yükleyici eşleşen .class dosyasını bulur (veya oluşturur), doğrular ve bağlar ve sınıf kullanıma hazırdır.
İş üç adımda gerçekleşir:
- Bul — Yükleyici, adlandırılan sınıf için bayt kodunu (bir JAR'dan, diskten, ağdan veya anında oluşturulmuş olarak) bulur.
- Doğrula ve bağla — JVM, bayt kodunun geçerli olup olmadığını kontrol eder ve diğer sınıflara yapılan referansları çözer.
- Kullan — Sınıf kullanıma hazırdır ve programınız onu örnekleyebilir.
İşte Java programlarının derleme zamanında hiç bahsedilmemiş kodu çalışma zamanında dinamik olarak yükleyebilmesinin nedeni. Yükleyicinin bulması için sınıf adı yeterlidir.
Sınıf yükleyici hiyerarşisi
Sınıf yükleyicileri bir üst-çocuk zinciri şeklinde düzenlenmiştir ve bunların çoğu önce üst öğesine sorar. Standart bir Java uygulaması üç yerleşik sınıf yükleyicisine sahiptir:
| Yükleyici | Yüklemeler | Amaç |
|---|---|---|
| Bootstrap | Temel Java çalışma zamanı sınıfları | java.lang.Object gibi temel türlerin her zaman aynı olmasını sağlar |
| Platform | Çekirdek dışında standart kütüphane modülleri | Java modülleri ve uzantıları |
| Uygulama | Programınızın kendi sınıfları | Programınızın belirttiği sınıf yolu |
Uygulama yükleyicisi bir sınıf için istendiğinde, normalde önce yukarıya devretmeye başlar. Platform yükleyicisini sorar, platform yükleyicisi de bootstrap yükleyicisini sorar, bu da onu yüklemeye çalışır. Sadece hiçbir üst yükleyici yükleyemezse çocuk yüklemeye çalışır. Bu devretme modelidir ve aynı sınıfın farklı adlar altında iki kez yüklenmesini engeller.
Sınıf kimliği ve nasıl çalışır
Bir sınıf hem adıyla hem de onu tanımlayan yükleyici tarafından tanımlanır. İki farklı yükleyici de com.example.MyClass adlı bir sınıfı yükleyebilir ve JVM bunları tamamen farklı türler olarak ele alır. Bu anlaşılması zor gelebilir, ancak Java'nın yapabileceği her ilginç şeyin temelini oluşturur.
Bootstrap Loader: java.lang.Object (the core Object)
Application Loader: java.lang.Object (if somehow re-loaded by app loader)
→ Two different types, same name
→ This breaks your program, which is why delegation prevents it
Özel sınıf yükleyicileri
Programlar kendi sınıf yükleyicilerini tanımlayabilir. Özel bir yükleyici, herhangi bir yerden bayt kodu okuyabilir: bir JAR dosyası, ağ, bir veritabanı veya anında oluşturduğu veya dönüştürdüğü bayt kodu. İşte nasıl:
- Eklenti sistemleri, derleme zamanında haberdar olmadan kodu dinamik olarak yükler.
- Uygulama sunucuları (Tomcat, JBoss), her biri kendi sınıf yükleyicisine sahip olmak üzere aynı JVM içinde birden fazla uygulama çalıştırır.
- Minecraft modları, yüklendikçe oyun sınıflarını yamalar.
Bunun Minecraft modları için neden önemli olduğu
Modlar özel sınıf yüklemesi nedeniyle var olurlar. Minecraft için bir mod yükleyici, oyunun kendi özel sınıf yükleyicisi aracılığıyla başlamasını sağlar, böylece oyun sınıflarını yüklenirken görebilir ve değiştirebilir. Bu kesme noktası sihrin gerçekleştiği yerdir.
Bir yükleyici disk ve JVM arasına oturduğunda, JVM tanımlamadan hemen önce bir sınıfı dönüştürebilir:
Disk: obfuscated Minecraft class
↓
Mod Loader (custom classloader)
↓ [bytecode transformation happens here]
↓
JVM: defines the patched class
↓
Memory: game runs with mods active
Bir mod, bir oyun yöntemini yeniden yazabilir, yeni davranış ekleyebilir, alanlar ekleyebilir; oyun JAR dosyasını diskte değiştirmeden. JVM'nin sonunda çalıştırdığı sınıf, mod çerçevesi tarafından değiştirilen sınıftır. Fabric, Forge ve diğer mod yükleyicileri Minecraft'ı tam olarak bu şekilde yamalar.
Tembel yükleme
Sınıflar başlangıçta yüklenmez. JVM, bir sınıf ilk kez kullanıldığında onu yükler. Buna tembel yükleme denir:
Program starts → JVM doesn't load String class yet
User calls System.out.println() → String is needed → Loader loads it
Bu, bir sınıf yükleyicisinin yalnızca kodunuzun temas ettiği sınıfları bulması ve yüklemesi gerektiği anlamına gelir. Kullanılmayan sınıflar belleğe girmez. Bunun nedeni, Minecraft başlangıcınızın bir süre alabilmesidir (modlar çok sayıda sınıf ekler), ancak sonsuza kadar donmamasıdır.
Sıkça Sorulan Sorular
İlk kullanımda, başlangıçta değil. Kodunuz bir türle ilk kez etkileşime girdiğinde, JVM bir sınıf yükleyicisinden onu bulmasını ve tanımlamasını ister. Buna tembel yükleme denir ve kullanılmayan kodun belleğe hiç girmemesinin nedenidir.
Bir sınıf yükleyicisi, kendisi denemeden önce sınıfının yüklenmesi için üst yükleyicisine başvurur. Üst yükleyici zinciri, başlangıç yükleyicisine kadar uzanır. Bu, aynı sınıfın farklı yükleyiciler tarafından aynı ad altında iki kez yüklenmesini engeller.
Evet, eğer farklı sınıf yükleyicileri bunları tanımlıyorsa. JVM, bir sınıfı hem adıyla hem de onu tanımlayan yükleyiciyle tanımlar, bu nedenle farklı yükleyicilerden gelen aynı adlı sınıflar ayrı türler olarak kabul edilir.
Yüklenirken sınıfları yakalayıp bellekte dönüştürmek. Özel bir yükleyici, diskin ve JVM'nin arasına oturarak, JVM sınıfı tanımlamadan önce bytecode'u değiştirir. İşte modların oyun jar dosyasını değiştirmeden Minecraft'ı yamaladığı yöntem.