Pemuat kelas
Ia digunakan untuk membekalkan kod bait yang disusun kepada JVM, yang biasanya disimpan dalam fail dengan sambungan.class
, tetapi juga boleh diperoleh daripada sumber lain, contohnya, dimuat turun melalui rangkaian atau dijana oleh aplikasi itu sendiri. Menurut spesifikasi Java SE, untuk menjalankan kod dalam JVM, anda perlu melengkapkan tiga langkah:
-
memuatkan bytecode daripada sumber dan mencipta contoh kelas
Class
ini termasuk mencari kelas yang diminta antara yang dimuatkan lebih awal, mendapatkan bytecode untuk memuatkan dan menyemak ketepatannya, mencipta contoh kelas
Class
(untuk bekerja dengannya semasa runtime), dan memuatkan kelas induk. Jika kelas induk dan antara muka belum dimuatkan, maka kelas berkenaan dianggap tidak dimuatkan. -
mengikat (atau menghubungkan)
Mengikut spesifikasi, peringkat ini dibahagikan kepada tiga peringkat lagi:
- Pengesahan , ketepatan kod bait yang diterima disemak.
- Penyediaan , memperuntukkan RAM untuk medan statik dan memulakannya dengan nilai lalai (dalam kes ini, permulaan eksplisit, jika ada, sudah berlaku pada peringkat permulaan).
- Resolusi , resolusi pautan simbolik jenis, medan dan kaedah.
-
memulakan objek yang diterima
di sini, tidak seperti perenggan sebelumnya, semuanya kelihatan jelas apa yang harus berlaku. Sudah tentu, ia akan menjadi menarik untuk memahami dengan tepat bagaimana ini berlaku.
- Kelas mesti dimuatkan sepenuhnya sebelum dipautkan.
- Kelas mesti diuji dan disediakan sepenuhnya sebelum ia dimulakan.
- Ralat resolusi pautan berlaku semasa pelaksanaan program, walaupun ia dikesan pada peringkat pemautan.
Jenis-jenis Pemuat Java
Terdapat tiga pemuat standard di Java, setiap satunya memuatkan kelas dari lokasi tertentu:-
Bootstrap ialah pemuat asas, juga dipanggil Primordial ClassLoader.
memuatkan kelas JDK standard daripada arkib rt.jar
-
Extension ClassLoader – pemuat sambungan.
memuatkan kelas sambungan, yang terletak dalam direktori jre/lib/ext secara lalai, tetapi boleh ditetapkan oleh sifat sistem java.ext.dirs
-
System ClassLoader – pemuat sistem.
memuatkan kelas aplikasi yang ditakrifkan dalam pembolehubah persekitaran CLASSPATH
ClassLoader kelas abstrak
Setiap pemuat, kecuali yang asas, adalah keturunan kelas abstrakjava.lang.ClassLoader
. Sebagai contoh, pelaksanaan pemuat sambungan ialah kelas sun.misc.Launcher$ExtClassLoader
, dan pemuat sistem ialah sun.misc.Launcher$AppClassLoader
. Pemuat asas adalah asli dan pelaksanaannya disertakan dalam JVM. Mana-mana kelas yang dilanjutkan java.lang.ClassLoader
boleh menyediakan caranya sendiri untuk memuatkan kelas dengan blackjack dan kelas yang sama ini. Untuk melakukan ini, adalah perlu untuk mentakrifkan semula kaedah yang sepadan, yang pada masa ini saya hanya boleh mempertimbangkan secara dangkal, kerana Saya tidak memahami isu ini secara terperinci. Di sini mereka:
package java.lang;
public abstract class ClassLoader {
public Class<?> loadClass(String name);
protected Class<?> loadClass(String name, boolean resolve);
protected final Class<?> findLoadedClass(String name);
public final ClassLoader getParent();
protected Class<?> findClass(String name);
protected final void resolveClass(Class<?> c);
}
loadClass(String name)
salah satu daripada beberapa kaedah awam, yang merupakan titik masuk untuk memuatkan kelas. Pelaksanaannya bermuara kepada memanggil kaedah lain yang dilindungi loadClass(String name, boolean resolve)
, yang perlu dibatalkan. Jika anda melihat Javadoc kaedah yang dilindungi ini, anda boleh memahami sesuatu seperti berikut: dua parameter dibekalkan sebagai input. Satu ialah nama binari kelas (atau nama kelas yang layak sepenuhnya) yang perlu dimuatkan. Nama kelas ditentukan dengan senarai semua pakej. Parameter kedua ialah bendera yang menentukan sama ada resolusi pautan simbolik diperlukan. Secara lalai ia adalah false , yang bermaksud pemuatan kelas malas digunakan. Selanjutnya, menurut dokumentasi, dalam pelaksanaan lalai kaedah, panggilan dibuat findLoadedClass(String name)
, yang menyemak sama ada kelas telah dimuatkan sebelum ini dan, jika ya, mengembalikan rujukan kepada kelas ini. Jika tidak, kaedah pemuatan kelas pemuat induk akan dipanggil. Jika tiada pemuat dapat mencari kelas yang dimuatkan, setiap daripada mereka, mengikut urutan terbalik, akan cuba mencari dan memuatkan kelas itu, mengatasi findClass(String name)
. Ini akan dibincangkan dengan lebih terperinci dalam bab "Skim Pemuatan Kelas". Dan akhirnya, akhir sekali, selepas kelas telah dimuatkan, bergantung pada bendera resolusi , ia akan diputuskan sama ada untuk memuatkan kelas melalui pautan simbolik. Contoh yang jelas ialah peringkat Resolusi boleh dipanggil semasa peringkat pemuatan kelas. Sehubungan itu, dengan memanjangkan kelas ClassLoader
dan mengatasi kaedahnya, pemuat tersuai boleh melaksanakan logiknya sendiri untuk menghantar bytecode ke mesin maya. Java juga menyokong konsep pemuat kelas "semasa". Pemuat semasa ialah pemuat yang memuatkan kelas yang sedang dilaksanakan. Setiap kelas mengetahui pemuat mana yang dimuatkan dan anda boleh mendapatkan maklumat ini dengan memanggilnya String.class.getClassLoader()
. Untuk semua kelas aplikasi, pemuat "semasa" biasanya adalah sistem.
Tiga Prinsip Pemuatan Kelas
-
Perwakilan
Permintaan untuk memuatkan kelas dihantar kepada pemuat induk dan percubaan untuk memuatkan kelas itu sendiri dibuat hanya jika pemuat induk tidak dapat mencari dan memuatkan kelas. Pendekatan ini membolehkan anda memuatkan kelas dengan pemuat yang sedekat mungkin dengan yang asas. Ini mencapai keterlihatan kelas maksimum. Setiap pemuat menyimpan rekod kelas yang dimuatkan olehnya, meletakkannya dalam cachenya. Set kelas ini dipanggil skop.
-
Keterlihatan
Pemuat hanya melihat kelas "nya" dan kelas "ibu bapa" dan tidak tahu tentang kelas yang dimuatkan oleh "anak"nya.
-
Keunikan
Kelas hanya boleh dimuatkan sekali. Mekanisme delegasi memastikan bahawa pemuat yang memulakan pemuatan kelas tidak membebankan kelas yang sebelum ini dimuatkan ke dalam JVM.
Skim pemuatan kelas
Apabila panggilan untuk memuatkan kelas berlaku, kelas ini dicari dalam cache kelas yang telah dimuatkan bagi pemuat semasa. Jika kelas yang dikehendaki belum dimuatkan sebelum ini, prinsip delegasi memindahkan kawalan kepada pemuat induk, yang terletak satu tahap lebih tinggi dalam hierarki. Pemuat induk juga cuba mencari kelas yang dikehendaki dalam cachenya. Jika kelas telah dimuatkan dan pemuat mengetahui lokasinya, maka objekClass
kelas itu akan dikembalikan. Jika tidak, carian akan diteruskan sehingga ia mencapai pemuat but asas. Jika pemuat asas tidak mempunyai maklumat tentang kelas yang diperlukan (iaitu, ia masih belum dimuatkan), kod bait kelas ini akan dicari di lokasi kelas yang diketahui oleh pemuat yang diberikan, dan jika kelas itu tidak dapat dimuatkan, kawalan akan kembali kepada pemuat anak, yang akan cuba memuatkan daripada sumber yang diketahuinya. Seperti yang dinyatakan di atas, lokasi kelas untuk pemuat asas ialah perpustakaan rt.jar, untuk pemuat sambungan - direktori dengan sambungan jre/lib/ext, untuk sistem satu - CLASSPATH, untuk pengguna ia boleh menjadi sesuatu yang berbeza . Oleh itu, kemajuan pemuatan kelas pergi ke arah yang bertentangan - dari pemuat akar ke pemuat semasa. Apabila kod bait kelas ditemui, kelas tersebut dimuatkan ke dalam JVM dan contoh jenis diperoleh Class
. Seperti yang anda boleh lihat dengan mudah, skema pemuatan yang diterangkan adalah serupa dengan pelaksanaan kaedah di atas loadClass(String name)
. Di bawah anda boleh melihat rajah ini dalam rajah.
Sebagai kesimpulan
Dalam langkah pertama mempelajari bahasa, tidak ada keperluan khusus untuk memahami cara kelas dimuatkan dalam Java, tetapi mengetahui prinsip asas ini akan membantu anda mengelakkan keputusasaan apabila menghadapi ralat sepertiClassNotFoundException
atau NoClassDefFoundError
. Nah, atau sekurang-kurangnya memahami secara kasar apa punca masalah itu. Oleh itu, pengecualian ClassNotFoundException
berlaku apabila kelas dimuatkan secara dinamik semasa pelaksanaan program, apabila pemuat tidak dapat mencari kelas yang diperlukan sama ada dalam cache atau sepanjang laluan kelas. Tetapi ralat NoClassDefFoundError
adalah lebih kritikal dan berlaku apabila kelas yang diperlukan tersedia semasa penyusunan, tetapi tidak kelihatan semasa pelaksanaan program. Ini boleh berlaku jika program terlupa memasukkan perpustakaan yang digunakannya. Nah, hakikat memahami prinsip struktur alat yang anda gunakan dalam kerja anda (tidak semestinya rendaman yang jelas dan terperinci dalam kedalamannya) menambah sedikit kejelasan kepada pemahaman proses yang berlaku di dalam mekanisme ini, yang, dalam giliran, membawa kepada penggunaan alat ini dengan yakin.
GO TO FULL VERSION