Java ClassLoader
Java ClassLoader הוא מחלקה מופשטת. זה שייך לא java.lang חֲבִילָה. הוא טוען שיעורים ממשאבים שונים. Java ClassLoader משמש לטעינת המחלקות בזמן ריצה. במילים אחרות, JVM מבצעת את תהליך הקישור בזמן ריצה. השיעורים נטענים ל-JVM בהתאם לצורך. אם מחלקה נטענת תלויה במחלקה אחרת, מחלקה זו נטענת גם כן. כאשר אנו מבקשים לטעון מחלקה, היא מאצילה את המחלקה להורה שלה. באופן זה, הייחודיות נשמרת בסביבת זמן הריצה. חיוני להפעיל תוכנית Java.
עקיפת שיטת java
Java ClassLoader מבוסס על שלושה עקרונות: מִשׁלַחַת , רְאוּת , ו ייחודיות .
סוגי ClassLoader
ב-Java, לכל ClassLoader יש מיקום מוגדר מראש שממנו הם טוענים קבצי מחלקה. ישנם סוגים הבאים של ClassLoader ב-Java:
Bootstrap Class Loader: הוא טוען קבצי מחלקות JDK סטנדרטיים מ-rt.jar ומחלקות ליבה אחרות. זה הורה של כל המעמיסים בכיתה. אין לזה שום הורה. כאשר אנו קוראים ל-String.class.getClassLoader() הוא מחזיר null, וכל קוד המבוסס עליו זורק את NullPointerException. זה נקרא גם Primordial ClassLoader. הוא טוען קבצי מחלקה מ-jre/lib/rt.jar. לדוגמה, מחלקת חבילת java.lang.
הרחבות Class Loader: הוא מאציל בקשת טעינת מחלקה להורה שלו. אם הטעינה של מחלקה לא מצליחה, היא טוענת מחלקות מספריית jre/lib/ext או כל ספרייה אחרת בתור java.ext.dirs. הוא מיושם על ידי sun.misc.Launcher$ExtClassLoader ב-JVM.
מטעין כיתת מערכת: הוא טוען מחלקות ספציפיות ליישום ממשתנה הסביבה CLASSPATH. ניתן להגדיר תוך כדי הפעלת תוכנית באמצעות אפשרויות שורת הפקודה -cp או classpath. זה בן של Extension ClassLoader. זה מיושם על ידי מחלקה sun.misc.Launcher$AppClassLoader. כל Java ClassLoader מיישם java.lang.ClassLoader.
כיצד ClassLoader עובד ב-Java
כאשר JVM מבקש מחלקה, הוא מפעיל את שיטת loadClass() של המחלקה java.lang.ClassLoader על ידי העברת השם המסווג במלואו של המחלקה. השיטה loadClass() קוראת לשיטת findLoadedClass() כדי לבדוק שהמחלקה כבר נטענה או לא. זה נדרש להימנע מטעינת המחלקה מספר פעמים.
אם המחלקה כבר נטענת, היא מאצילה את הבקשה להורה ClassLoader כדי לטעון את המחלקה. אם ה-ClassLoader לא מוצא את המחלקה, הוא מפעיל את המתודה findClass() כדי לחפש את המחלקות במערכת הקבצים. התרשים הבא מראה כיצד ClassLoader טוען מחלקה ב-Java באמצעות האצלה.
נניח שיש לנו מחלקה ספציפית ליישום Demo.class. הבקשה לטעינה של קבצי מחלקה זו עוברת ל- Application ClassLoader. הוא מעביר ל-ClassLoader, תוסף האב שלו. יתר על כן, הוא מעביר ל- Bootstrap ClassLoader. חפש את המחלקה הזו ב-rt.jar ומכיוון שהמחלקה הזו לא שם. כעת בקש העברה אל Extension ClassLoader אשר מחפש את הספרייה jre/lib/ext ומנסה לאתר את המחלקה הזו שם. אם המחלקה נמצאת שם, Extension ClassLoader טוען את המחלקה הזו. Application ClassLoader אף פעם לא טוען את המחלקה הזו. כאשר התוסף ClassLoader אינו טוען אותו, אז Application ClaasLoader טוען אותו מ-CLASSPATH ב-Java.
עקרון הנראות קובע ש-ClassLoader הילד יכול לראות את המחלקה שנטענה על-ידי ה-ClassLoader האב, אך להיפך אינו נכון. זה אומר שאם Application ClassLoader טוען Demo.class, במקרה כזה, ניסיון לטעון את Demo.class במפורש באמצעות Extension ClassLoader זורק java.lang.ClassNotFoundException.
על פי עקרון הייחודיות, מחלקה שנטענת על ידי ההורה לא צריכה להיטען שוב על ידי Child ClassLoader. לכן, אפשר לכתוב מחלקה loader שמפר את עקרונות האצלה וייחודיות וטוען מחלקה בעצמו.
בקיצור, מטעין הכיתה פועל לפי הכלל הבא:
- זה בודק אם המחלקה כבר נטענת.
- אם הכיתה לא נטענת, בקש ממטעין הכיתה ההורה לטעון את הכיתה.
- אם מטעין מחלקות האב אינו יכול לטעון מחלקה, נסה לטעון אותו במטען מחלקות זה.
שקול את הדוגמה הבאה:
public class Demo { public static void main(String args[]) { System.out.println('How are you?'); } }
הידור והפעל את הקוד לעיל באמצעות הפקודה הבאה:
javac Demo.java java -verbose:class Demo
-verbose:class: הוא משמש להצגת המידע על מחלקות הנטענות על ידי JVM. זה שימושי בעת שימוש ב-class loader לטעינת מחלקות באופן דינמי. האיור הבא מציג את הפלט.
אנו יכולים לראות שמחלקות זמן ריצה הנדרשות על ידי מחלקת היישום (Demo) נטענות תחילה.
כאשר השיעורים נטענים
יש רק שני מקרים:
- כאשר קוד הביט החדש מבוצע.
- כאשר קוד הביט עושה הפניה סטטית למחלקה. לדוגמה, System.out .
טעינת מחלקה סטטית לעומת דינמית
השיעורים נטענים באופן סטטי עם אופרטור 'חדש'. טעינת מחלקה דינמית מפעילה את הפונקציות של מטעין מחלקות בזמן ריצה באמצעות שיטת Class.forName() .
ההבדל בין loadClass() ל-Class.forName()
השיטה loadClass() טוענת רק את המחלקה אך אינה מאתחלת את האובייקט. בעוד ששיטת Class.forName() מאתחלת את האובייקט לאחר טעינתו. לדוגמה, אם אתה משתמש ב-ClassLoader.loadClass() כדי לטעון את מנהל ההתקן של JDBC, טוען המחלקה אינו מאפשר לטעון את מנהל ההתקן של JDBC.
השיטה java.lang.Class.forName() מחזירה את ה-Class Object יחד עם המחלקה או מתממשקת עם שם המחרוזת הנתון. זה זורק ClassNotFoundException אם המחלקה לא נמצאת.
דוגמא
בדוגמה זו, מחלקה java.lang.String נטען. הוא מדפיס את שם המחלקה, שם החבילה והשמות של כל השיטות הזמינות של מחלקה String. אנו משתמשים ב-Class.forName() בדוגמה הבאה.
מעמד: מייצג אובייקט Class שיכול להיות מכל סוג (? הוא תו כללי). סוג המחלקה מכיל מטא-מידע על מחלקה. לדוגמה, סוג String.class הוא Class. השתמש ב-Class אם המחלקה שמעצבת אינה ידועה.
getDeclaredMethod(): מחזירה מערך המכיל אובייקטי Method המשקפים את כל השיטות המוצהרות של המחלקה או הממשק המיוצגים על ידי אובייקט Class זה, כולל שיטות ציבוריות, מוגנת, ברירת מחדל (חבילה) ושיטות פרטיות, אך לא כולל שיטות בירושה.
getName(): הוא מחזיר את שם השיטה המיוצג על ידי אובייקט השיטה הזה, כמחרוזת.
import java.lang.reflect.Method; public class ClassForNameExample { public static void main(String[] args) { try { Class cls = Class.forName('java.lang.String'); System.out.println('Class Name: ' + cls.getName()); System.out.println('Package Name: ' + cls.getPackage()); Method[] methods = cls.getDeclaredMethods(); System.out.println('-----Methods of String class -------------'); for (Method method : methods) { System.out.println(method.getName()); } } catch (ClassNotFoundException e) { e.printStackTrace(); } } }
תְפוּקָה
Class Name: java.lang.String Package Name: package java.lang -----Methods of String class ------------- value coder equals length toString hashCode getChars ------ ------ ------ intern isLatin1 checkOffset checkBoundsOffCount checkBoundsBeginEnd access0 access0