מדריך לדוגמה של השתקפות Java

השתקפות Java מספקת אפשרות לבדיקה ושינוי של התנהגות הרצת היישום. השתקפות ב-Java היא אחת מנושאי העמוק של גרסת היסוד של Java. באמצעות השתקפות Java אנו יכולים לבדוק מחלקה, ממשק, אינומרציה, לקבל את מבנה השדות והשיטות שלהם בזמן ריצה אף על פי שהמחלקה אינה נגישה בזמן ההרכבה. ניתן גם להשתמש בהשתקפות כדי ליצור אובייקט, לקרוא את השיטות שלו, לשנות ערכי שדותיו.

השתקפות Java

  1. השתקפות ב-Java
  2. שיקופים ב-Java עבור מחלקות
  3. רפלקציה ב-Java עבור שדות
  4. רפלקציה ב-Java עבור שיטות
  5. רפלקציה ב-Java עבור בנאי
  6. רפלקציה ב-Java עבור הערות

  1. רפלקציה ב-Java

רפלקציה ב-Java היא מושג עוצמתי מאוד והוא מועט תועד בתכנות רגיל, אך זהו עמוד התמיכה לרוב הגרמים, המסגרות J2EE ב-Java. כמה מהמסגרות שמשתמשות ברפלקציה ב-Java הן:

  1. JUnit – משתמשת ברפלקציה כדי לפרק את ההערה @Test כדי לקבל את שיטות הבדיקה ולקרוא להן.
  2. Spring – הזרמת תלות, ניתן לקרוא עוד ב־הזרמת תלות ב-Spring
  3. Tomcat תיקשורת אינטרנטית להעברת הבקשה למודול הנכון על ידי פריסת קבצי ה־web.xml שלהם וה־URI של הבקשה.
  4. Eclipse השלמה אוטומטית של שמות השיטות
  5. סטראטס
  6. היברנייט

הרשימה אינה נגמרת וכולם משתמשים בהיקף רחב של טכנולוגיות, וכולן משתמשות בפעולת השקפת יוצר (Java Reflection). זאת מכיוון שכל אלו הפריימוורקים אין להם מידע וגישה למחלקות, ממשקים, ושיטות שמוגדרות על ידי המשתמש. יש להימנע משימוש בשקפת יוצר בתכנות הרגיל, במקרה בו יש גישה למחלקות ולממשקים דרך דרכים רגילות כיוון לבעיות אלו:

  • ביצוע רע – מכיוון ששקפת יוצר של ג'אווה פותרת את סוגי הנתונים דינמית, היא משתמשת בעיבוד שכולל סריקת מסלולי הקבצים כדי למצוא את המחלקה לטעינה, מה שגורם לביצוע איטי.
  • מגבלות אבטחה – שקפת יוצר דורשת הרשאות בזמן ריצה שאינן תמיד זמינות למערכת הפועלת תחת מנהל אבטחה. זה יכול לגרום לכשלון בביצועי היישום בזמן ריצה בשל מנהל האבטחה.
  • בעיות אבטחה – באמצעות שקפת יוצר, ניתן לגשת לקטעי קוד שאין לנו אישור לגשת אליהם, לדוגמה יש אפשרות לגשת לשדות פרטיים במחלקה ולשנות את ערכם. זה יכול להיות איום לאבטחת המערכת ולגרום להתנהגות אנומלית של היישום שלך.
  • תחזוקה גבוהה – קוד שקפת יוצר הוא קשה להבנה ולניפוי שגיאות, וכמו כן, אי אפשר לזהות בעיות בקוד בזמן ההדקה כיוון קבצי המחלקות ייתכן שלא יהיו זמינים, מה שהופך את הקוד לפחות גמיש וקשה לתחזוקה.
  1. שקפיות Java עבור קלאסים

ב-Java, כל אובייקט הוא או טיפוס פרימיטיבי או ייחודי. כל הקלאסים, האינומים, והמערכים הם טיפוסי ייחודי ומורשים מתוך java.lang.Object. טיפוסי הפרימיטיביים הם – boolean, byte, short, int, long, char, float, ו-double. java.lang.Class הוא נקודת הכניסה לכל הפעולות של השקפיות. לכל סוג של אובייקט, JVM מייצרת מופע בלתי ניתן לשינוי של java.lang.Class המספק שיטות לבדיקת מאפייני הריצה של האובייקט ויצירת אובייקטים חדשים, קריאה לשיטות שלו וקבלת/הגדרת שדות האובייקט. בסעיף זה, נבחן שיטות חשובות של Class, לנוחות, אני יוצר מספר קלאסים ואינטרפייסים עם מורשיות ביררות.

package com.journaldev.reflection;

public interface BaseInterface {
	
	public int interfaceInt=0;
	
	void method1();
	
	int method2(String str);
}
package com.journaldev.reflection;

public class BaseClass {

	public int baseInt;
	
	private static void method3(){
		System.out.println("Method3");
	}
	
	public int method4(){
		System.out.println("Method4");
		return 0;
	}
	
	public static int method5(){
		System.out.println("Method5");
		return 0;
	}
	
	void method6(){
		System.out.println("Method6");
	}
	
	// public class פנימית
	public class BaseClassInnerClass{}
		
	// חברה ציבורית enum
	public enum BaseClassMemberEnum{}
}
package com.journaldev.reflection;

@Deprecated
public class ConcreteClass extends BaseClass implements BaseInterface {

	public int publicInt;
	private String privateString="private string";
	protected boolean protectedBoolean;
	Object defaultObject;
	
	public ConcreteClass(int i){
		this.publicInt=i;
	}

	@Override
	public void method1() {
		System.out.println("Method1 impl.");
	}

	@Override
	public int method2(String str) {
		System.out.println("Method2 impl.");
		return 0;
	}
	
	@Override
	public int method4(){
		System.out.println("Method4 overriden.");
		return 0;
	}
	
	public int method5(int i){
		System.out.println("Method4 overriden.");
		return 0;
	}
	
	// פנימי קבצי מחלקה
	public class ConcreteClassPublicClass{}
	private class ConcreteClassPrivateClass{}
	protected class ConcreteClassProtectedClass{}
	class ConcreteClassDefaultClass{}
	
	// חברה enum
	enum ConcreteClassDefaultEnum{}
	public enum ConcreteClassPublicEnum{}
	
	// חברה ממשק
	public interface ConcreteClassPublicInterface{}

}

בואו נסתכל על כמה מהשיטות החשובות של רפלקציה עבור מחלקות.

קבל אובייקט מחלקה

אנו יכולים לקבל את המחלקה של אובייקט באמצעות שלוש שיטות – דרך משתנה סטטי class, באמצעות שיטת getClass() של אובייקט ו java.lang.Class.forName(String fullyClassifiedClassName). עבור סוגי הנתונים הפרימיטיביים ומערכות, אנו יכולים להשתמש במשתנה סטטי class. קלטות העטיפה מספקות משתנה סטטי נוסף TYPE לקבלת המחלקה.

// קבלת מחלקה באמצעות רפלקציה
Class concreteClass = ConcreteClass.class;
concreteClass = new ConcreteClass(5).getClass();
try {
	// השיטה למטה משמשת ברוב הפעמים בפריימוורקים כמו JUnit
	// התלות בתכנות המתואם של Spring, תכנית האינטרנט של Tomcat
	// השלמה אוטומטית של Eclipse של שמות השיטות, היברנייט, Struts2 וכו'
	// כי ConcreteClass אינו זמין בזמן הקומפילציה
	concreteClass = Class.forName("com.journaldev.reflection.ConcreteClass");
} catch (ClassNotFoundException e) {
	e.printStackTrace();
}
System.out.println(concreteClass.getCanonicalName()); // prints com.journaldev.reflection.ConcreteClass

// עבור סוגי נתונים פרימיטיביים, קלטות העטיפה ומערכות
Class booleanClass = boolean.class;
System.out.println(booleanClass.getCanonicalName()); // prints boolean

Class cDouble = Double.TYPE;
System.out.println(cDouble.getCanonicalName()); // prints double

Class cDoubleArray = Class.forName("[D");
System.out.println(cDoubleArray.getCanonicalName()); //prints double[]

Class twoDStringArray = String[][].class;
System.out.println(twoDStringArray.getCanonicalName()); // prints java.lang.String[][]

getCanonicalName() מחזיר את השם הקנוני של המחלקה התחתונה. שים לב ש- java.lang.Class משתמש ב- Generics, זה עוזר לפריימוורקים לוודא שהמחלקה שהושגה היא מחלקת מחלקת הבסיס של הפריימוורק. צפה ב- מדריך ל- Java Generics כדי ללמוד על Generics ועל הכרטיסים הפרועים שלו.

קבל מחלקת הורה

getSuperclass() השיטה על אובייקט מחלקה מחזירה את המחלקה האב של המחלקה. אם המחלקה הזו מייצגת את מחלקת ה- Object, ממשק, סוג פרימיטיבי או ריק, אז null יוחזר. אם האובייקט הזה מייצג מחלקת מערך, אז אובייקט מחלקת ה- Object יוחזר.

Class<?> superClass = Class.forName("com.journaldev.reflection.ConcreteClass").getSuperclass();
System.out.println(superClass); // prints "class com.journaldev.reflection.BaseClass"
System.out.println(Object.class.getSuperclass()); // prints "null"
System.out.println(String[][].class.getSuperclass());// prints "class java.lang.Object"

קבל מחלקות חברות ציבוריות

getClasses() שיטת ייצוג של אובייקט מחזירה מערך הכולל אובייקטים מסוג Class המייצגים את כל המחלקות הציבוריות, הממשקים והאינומרציות שהם חברים של המחלקה שמייצג האובייקט Class זה. זה כולל חברים של מחלקה וממשק ציבוריים הנירתדים ממחלקות אב וחברים של מחלקה וממשק ציבוריים שהוגדרו על ידי המחלקה. השיטה מחזירה מערך באורך 0 אם לא קיימות מחלקות או ממשקים ציבוריים במחלקה זו או אם האובייקט Class זה מייצג סוג פרימיטיבי, מחלקת מערך או void.

Class[] classes = concreteClass.getClasses();
//[class com.journaldev.reflection.ConcreteClass$ConcreteClassPublicClass, 
//class com.journaldev.reflection.ConcreteClass$ConcreteClassPublicEnum, 
//interface com.journaldev.reflection.ConcreteClass$ConcreteClassPublicInterface,
//class com.journaldev.reflection.BaseClass$BaseClassInnerClass, 
//class com.journaldev.reflection.BaseClass$BaseClassMemberEnum]
System.out.println(Arrays.toString(classes));

קבל כיתות מצוינות

getDeclaredClasses() שיטה מחזירה מערך של אובייקטים מסוג Class המשקפים את כל המחלקות והממשקים המוגדרים כחברים של המחלקה שמייצג האובייקט Class זה. המערך שמוחזר אינו כולל מחלקות שהוגדרו במחלקות אב וממשקים.

//קובלת את כל המחלקות, הממשקים והאינומרציות שמוגדרות באופן ישיר ב-\texttt{ConcreteClass
Class[] explicitClasses = Class.forName("com.journaldev.reflection.ConcreteClass").getDeclaredClasses();
}//מדפיסה [class com.journaldev.reflection.ConcreteClass$ConcreteClassDefaultClass, 
//class com.journaldev.reflection.ConcreteClass$ConcreteClassDefaultEnum, 
//class com.journaldev.reflection.ConcreteClass$ConcreteClassPrivateClass, 
//class com.journaldev.reflection.ConcreteClass$ConcreteClassProtectedClass, 
//class com.journaldev.reflection.ConcreteClass$ConcreteClassPublicClass, 
//class com.journaldev.reflection.ConcreteClass$ConcreteClassPublicEnum, 
//interface com.journaldev.reflection.ConcreteClass$ConcreteClassPublicInterface]
System.out.println(Arrays.toString(explicitClasses));

קבל את המחלקה המכילה

getDeclaringClass() מתודה מחזירה את אובייקט המחלקה המייצגת את המחלקה שבה הוא הוגדר.

Class innerClass = Class.forName("com.journaldev.reflection.ConcreteClass$ConcreteClassDefaultClass");
//מדפיסה com.journaldev.reflection.ConcreteClass
System.out.println(innerClass.getDeclaringClass().getCanonicalName());
System.out.println(innerClass.getEnclosingClass().getCanonicalName());

מקבלת את שם החבילה

getPackage() מתודה מחזירה את החבילה של מחלקה זו. ניתן לקרוא למתודה getName() של Package כדי לקבל את שם החבילה.

//מדפיס "com.journaldev.reflection"
System.out.println(Class.forName("com.journaldev.reflection.BaseInterface").getPackage().getName());

משיג את המאפיינים של המחלקה

getModifiers() מתודה מחזירה את הייצוג המספרי של מאפייני המחלקה, אפשר להשתמש במתודה java.lang.reflect.Modifier.toString() כדי לקבל את זה בפורמט מחרוזת כפי שמשמש בקוד המקור.

System.out.println(Modifier.toString(concreteClass.getModifiers())); //prints "public"
//מדפיס "public abstract interface"
System.out.println(Modifier.toString(Class.forName("com.journaldev.reflection.BaseInterface").getModifiers())); 

משיג פרמטרי סוג

getTypeParameters() מחזיר את מערך ה- TypeVariable אם ישנם פרמטרים של סוג הקשורים למחלקה. פרמטרי הסוג מוחזרים באותו סדר שנקבע.

//משיג פרמטרי סוג (גנריקים)
TypeVariable[] typeParameters = Class.forName("java.util.HashMap").getTypeParameters();
for(TypeVariable t : typeParameters)
System.out.print(t.getName()+",");

משיג תחומים ממומנים

getGenericInterfaces() מתודה מחזירה את מערך הממומנים שממומנים על ידי המחלקה עם מידע גנרי. יש גם אפשרות להשתמש ב- getInterfaces() כדי לקבל את הייצוג המחלקתי של כל ממומן שמומנה.

Type[] interfaces = Class.forName("java.util.HashMap").getGenericInterfaces();
//מדפיס "[java.util.Map, interface java.lang.Cloneable, interface java.io.Serializable]"
System.out.println(Arrays.toString(interfaces));
//מדפיס "[interface java.util.Map, interface java.lang.Cloneable, interface java.io.Serializable]"
System.out.println(Arrays.toString(Class.forName("java.util.HashMap").getInterfaces()));		

קבל את כל המתודות הציבוריות

המתודה getMethods() מחזירה את מערך המתודות הציבוריות של הכיתה כולל המתודות הציבוריות של המחלקות העליונות והממשקים העליונים.

Method[] publicMethods = Class.forName("com.journaldev.reflection.ConcreteClass").getMethods();
//מדפיס מתודות ציבוריות של ConcreteClass, BaseClass, Object
System.out.println(Arrays.toString(publicMethods));

קבל את כל הבנאים הציבוריים

המתודה getConstructors() מחזירה את רשימת הבנאים הציבוריים של המחלקה אותה מייחסים לאובייקט.

//קבל את כל הבנאים הציבוריים
Constructor[] publicConstructors = Class.forName("com.journaldev.reflection.ConcreteClass").getConstructors();
//מדפיס בנאים ציבוריים של ConcreteClass
System.out.println(Arrays.toString(publicConstructors));

קבל את כל השדות הציבוריים

המתודה getFields() מחזירה את מערך השדות הציבוריים של המחלקה כולל השדות הציבוריים של המחלקות העליונות והממשקים העליונים.

//קבל את כל השדות הציבוריים
Field[] publicFields = Class.forName("com.journaldev.reflection.ConcreteClass").getFields();
//מדפיס שדות ציבוריים של ConcreteClass, של המחלקה האב ושל הממשקים האב
System.out.println(Arrays.toString(publicFields));

קבל את כל האנוטציות

getAnnotations() המתודה מחזירה את כל האנוטציות עבור האלמנט, אנו יכולים להשתמש בה עם מחלקות, שדות ושיטות גם. שימו לב שרק אנוטציות זמינות עם מראה הרצת RUNTIME זמינות עם השקפת רפלקציה, בדקו את מדריך האנוטציות של Java. נבחן את זה בעומק יותר בחלקים מאוחרים.

java.lang.annotation.Annotation[] annotations = Class.forName("com.journaldev.reflection.ConcreteClass").getAnnotations();
//מדפיס [@java.lang.Deprecated()]
System.out.println(Arrays.toString(annotations));
  1. רפלקציה ב-Java עבור שדות

API רפלקציה מספק מספר מתודות לנתח שדות של מחלקה ולשנות את ערכיהם בזמן ריצה, בחלק זה נבחן כמה מהפונקציות של רפלקציה המשמשות באופן נפוץ לשיטות.

קבל שדה ציבורי

בחלק האחרון, ראינו כיצד לקבל את רשימת כל השדות הציבוריים של מחלקה. ה- Reflection API מספק גם שיטה לקבלת שדה ציבורי מסוים של מחלקה דרך השיטה getField(). שיטה זו מחפשת את השדה בהפניה למחלקה המסוימת ואז בממשקי המופע ולבסוף במחלקות העל.

Field field = Class.forName("com.journaldev.reflection.ConcreteClass").getField("interfaceInt");

הקריאה לעיל תחזיר את השדה מ- BaseInterface שמיושם על ידי ConcreteClass. אם לא נמצא שדה, היא תזרוק את NoSuchFieldException.

מחלקת המצה עבור שדה

ניתן להשתמש ב- getDeclaringClass() של אובייקט השדה כדי לקבל את המחלקה המצה את השדה.

try {
	Field field = Class.forName("com.journaldev.reflection.ConcreteClass").getField("interfaceInt");
	Class<?> fieldClass = field.getDeclaringClass();
	System.out.println(fieldClass.getCanonicalName()); //prints com.journaldev.reflection.BaseInterface
} catch (NoSuchFieldException | SecurityException e) {
	e.printStackTrace();
}

קבל סוג שדה

השיטה getType() מחזירה את אובייקט המחלקה עבור סוג השדה המוגדר, אם השדה הוא סוג פרימיטיבי, היא מחזירה את אובייקט המחלקה של המעטפת.

Field field = Class.forName("com.journaldev.reflection.ConcreteClass").getField("publicInt");
Class<?> fieldType = field.getType();
System.out.println(fieldType.getCanonicalName()); //prints int			

קבלה/קביעת ערך שדה ציבורי

אנו יכולים לקבל ולקבוע את ערך השדה באובייקט באמצעות השתקפות.

Field field = Class.forName("com.journaldev.reflection.ConcreteClass").getField("publicInt");
ConcreteClass obj = new ConcreteClass(5);
System.out.println(field.get(obj)); //prints 5
field.setInt(obj, 10); //setting field value to 10 in object
System.out.println(field.get(obj)); //prints 10

שיטת get() מחזירה אובייקט, ולכן אם השדה הוא סוג יסודי, היא מחזירה את ה-Wrapper Class המתאימה. אם השדה הוא סטטי, נוכל להעביר את האובייקט כ- null בשיטת get(). ישנן מספר של שיטות set*() להגדיר אובייקט לשדה או להגדיר סוגים שונים של סוגי יסוד לשדה. אנו יכולים לקבל את סוג השדה ולאחר מכן לקרוא לפונקציה הנכונה כדי להגדיר את ערך השדה בצורה נכונה. אם השדה הוא קבוע, אז שיטות ה-set() זורקות java.lang.IllegalAccessException.

קבלה/קביעת ערך שדה פרטי

אנו יודעים ששדות ושיטות פרטיים אינם נגישים מחוץ למחלקה, אך באמצעות השתקפות, אנו יכולים לקבל/לקבוע את ערך השדה הפרטי על ידי כיבוי בדיקת הגישה של ג'אווה למודיפיקטורים של השדה.

Field privateField = Class.forName("com.journaldev.reflection.ConcreteClass").getDeclaredField("privateString");
//כיבוי בדיקת גישה עם שיחה לשיטה שלמטה
privateField.setAccessible(true);
ConcreteClass objTest = new ConcreteClass(1);
System.out.println(privateField.get(objTest)); // prints "private string"
privateField.set(objTest, "private string updated");
System.out.println(privateField.get(objTest)); //prints "private string updated"
  1. Java Reflection for Methods

באמצעות השקפה פרסונלית אנו יכולים לקבל מידע אודות שיטה ולקרוא אותה גם. בסעיף זה, נלמד דרכים שונות לקבל שיטה, לקרוא לשיטה ולגשת לשיטות פרטיות.

קבלת שיטה ציבורית

ניתן להשתמש בפונקציה getMethod() כדי לקבל שיטה ציבורית של מחלקה, עלינו להעביר את שם השיטה וסוגי הפרמטרים של השיטה. אם השיטה לא נמצאת במחלקה, ממשק ה-Reflection יחפש אותה במחלקה האב. בדוגמה למטה, אני מקבל את השיטה put() של HashMap באמצעות השקפה פרסונית. הדוגמה גם מראה איך לקבל סוגי הפרמטרים, מודיפיקטורי השיטה וסוג ההחזרה של השיטה.

Method method = Class.forName("java.util.HashMap").getMethod("put", Object.class, Object.class);
//קבלת סוגי פרמטרים של השיטה, מדפיס "[class java.lang.Object, class java.lang.Object]"
System.out.println(Arrays.toString(method.getParameterTypes()));
//קבלת סוג ההחזרה של השיטה, מחזיר "class java.lang.Object", ייצוג מחלקה לטיפול בערך הריק (void)
System.out.println(method.getReturnType());
//קבלת מודיפיקטורים של השיטה
System.out.println(Modifier.toString(method.getModifiers())); //prints "public"

קריאה לשיטה ציבורית

ניתן להשתמש בשיטת invoke() של אובייקט Method כדי לקרוא לשיטה, בקוד הדוגמה למטה אני קורא לשיטת put על HashMap באמצעות רפלקציה.

Method method = Class.forName("java.util.HashMap").getMethod("put", Object.class, Object.class);
Map<String, String> hm = new HashMap<>();
method.invoke(hm, "key", "value");
System.out.println(hm); // prints {key=value}

אם השיטה היא סטטית, נוכל להעביר NULL כארגומנט אובייקט.

קריאה לשיטות פרטיות

ניתן להשתמש בשיטה getDeclaredMethod() כדי לקבל את השיטה הפרטית ואז לכבות את בדיקת הגישה כדי לקרוא לה, הדוגמה למטה מראה כיצד ניתן לקרוא לשיטה3() של BaseClass שהיא סטטית ואין לה פרמטרים.

// קריאה לשיטה פרטית
Method method = Class.forName("com.journaldev.reflection.BaseClass").getDeclaredMethod("method3", null);
method.setAccessible(true);
method.invoke(null, null); //prints "Method3"
  1. רפלקציה ב-Java לבניית בונאים

ה-Reflection API מספקת שיטות לקבלת הבנאים של מחלקה לניתוח ואפשר ליצור מופעים חדשים של מחלקה על ידי קריאה לבנאי. כבר למדנו איך לקבל את כל הבנאים הציבוריים.

לקבלת בנאי ציבורי

ניתן להשתמש בשיטת getConstructor() על ייצוג המחלקה של האובייקט כדי לקבל בנאי ציבורי מסוים. בדוגמה שלמטה מוצגת איך לקבל את הבנאי של ConcreteClass שהוגדר למעלה ואת בנאי הארגומנטים שלא דורש ארגומנטים של HashMap. הדוגמה מציגה גם איך לקבל מערך של סוגי פרמטרים עבור הבנאי.

Constructor constructor = Class.forName("com.journaldev.reflection.ConcreteClass").getConstructor(int.class);
//קבלת פרמטרי הבנאי
System.out.println(Arrays.toString(constructor.getParameterTypes())); // prints "[int]"
		
Constructor hashMapConstructor = Class.forName("java.util.HashMap").getConstructor(null);
System.out.println(Arrays.toString(hashMapConstructor.getParameterTypes())); // prints "[]"

יצירת אובייקט באמצעות בנאי

ניתן להשתמש בשיטת newInstance() על אובייקט הבנאי כדי ליצור מופע חדש של המחלקה. מאחר שאנו משתמשים ברפלקציה כאשר אין לנו את מידע המחלקות בזמן קומפילציה, ניתן להשייך אותו לאובייקט ולאחר מכן להשתמש ברפלקציה נוספת כדי לגשת אל שדותיו ולקרוא לשיטותיו.

Constructor constructor = Class.forName("com.journaldev.reflection.ConcreteClass").getConstructor(int.class);
//קבלת פרמטרי הבנאי
System.out.println(Arrays.toString(constructor.getParameterTypes())); // prints "[int]"
		
Object myObj = constructor.newInstance(10);
Method myObjMethod = myObj.getClass().getMethod("method1", null);
myObjMethod.invoke(myObj, null); //prints "Method1 impl."

Constructor hashMapConstructor = Class.forName("java.util.HashMap").getConstructor(null);
System.out.println(Arrays.toString(hashMapConstructor.getParameterTypes())); // prints "[]"
HashMap myMap = (HashMap) hashMapConstructor.newInstance(null);
  1. התקפית להערות

ההערות נכנסו לשימוש ב-Java 1.5 כדי לספק מידע על מטא-נתונים של המחלקה, השיטות או השדות וכעת משמשות מאוד במסגרות כמו Spring ו-Hibernate. גם ממשק ה-API לרפלקציה הואההומל לספק תמיכה בניתוח ההערות בזמן ריצה. באמצעות ממשק הרפלקציה אנו יכולים לנתח הערות שהמדיניות של שמירתן היא בזמן ריצה. כבר כתבתי מדריך מפורט על ההערות וכיצד אפשר להשתמש ב-API של הרפלקציה לניתוח ההערות, אז אני ממליץ לך לבדוק את מדריך ההערות ב-Java. זהו הכל לדוגמת הרפלקציה של Java, אני מקווה שאהבת את המדריך והבנת את חשיבות ממשק הרפלקציה של Java.

Source:
https://www.digitalocean.com/community/tutorials/java-reflection-example-tutorial